diff options
Diffstat (limited to 'src/H5AC2.c')
-rw-r--r-- | src/H5AC2.c | 4790 |
1 files changed, 4790 insertions, 0 deletions
diff --git a/src/H5AC2.c b/src/H5AC2.c new file mode 100644 index 0000000..a053b36 --- /dev/null +++ b/src/H5AC2.c @@ -0,0 +1,4790 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: H5AC2.c + * Jul 9 1997 + * Robb Matzke <matzke@llnl.gov> + * + * Purpose: Functions in this file implement a cache for + * things which exist on disk. All "things" associated + * with a particular HDF file share the same cache; each + * HDF file has it's own cache. + * + * Modifications: + * + * Robb Matzke, 4 Aug 1997 + * Added calls to H5E. + * + * Quincey Koziol, 22 Apr 2000 + * Turned on "H5AC2_SORT_BY_ADDR" + * + * John Mainzer, 5/19/04 + * Complete redesign and rewrite. See the header comments for + * H5AC2_t for an overview of what is going on. + * + * John Mainzer, 6/4/04 + * Factored the new cache code into a separate file (H5C.c) to + * facilitate re-use. Re-worked this file again to use H5C. + * + * John Mainzer, 10/18/07 + * Copied H5AC2.c to H5AC22.c and reworked to use H5C2 instead of H5C. + * All this is in support of cache API modifications needed for + * journaling. + * + *------------------------------------------------------------------------- + */ + +#define H5C2_PACKAGE /*suppress error about including H5C2pkg */ +#define H5AC2_PACKAGE /*suppress error about including H5AC2pkg */ +#define H5F_PACKAGE /*suppress error about including H5Fpkg */ + +/* Interface initialization */ +#define H5_INTERFACE_INIT_FUNC H5AC2_init_interface + +#ifdef H5_HAVE_PARALLEL +#include <mpi.h> +#endif /* H5_HAVE_PARALLEL */ + +#include "H5private.h" /* Generic Functions */ +#include "H5AC2pkg.h" /* Metadata cache */ +#include "H5C2pkg.h" /* Cache */ +#include "H5Dprivate.h" /* Dataset functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Fpkg.h" /* Files */ +#include "H5FDprivate.h" /* File drivers */ +#include "H5FLprivate.h" /* Free Lists */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Pprivate.h" /* Property lists */ + + +#ifdef H5_HAVE_PARALLEL + +/* Declare a free list to manage the H5AC2_aux_t struct */ +H5FL_DEFINE_STATIC(H5AC2_aux_t); + +#endif /* H5_HAVE_PARALLEL */ + +/**************************************************************************** + * + * structure H5AC2_slist_entry_t + * + * The dirty entry list maintained via the d_slist_ptr field of H5AC2_aux_t + * and the cleaned entry list maintained via the c_slist_ptr field of + * H5AC2_aux_t are just lists of the file offsets of the dirty/cleaned + * entries. Unfortunately, the slist code makes us define a dynamically + * allocated structure to store these offsets in. This structure serves + * that purpose. Its fields are as follows: + * + * magic: Unsigned 32 bit integer always set to + * H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC. This field is used to + * validate pointers to instances of H5AC2_slist_entry_t. + * + * addr: file offset of a metadata entry. Entries are added to this + * list (if they aren't there already) when they are marked + * dirty in an unprotect, inserted, or renamed. They are + * removed when they appear in a clean entries broadcast. + * + ****************************************************************************/ + +#ifdef H5_HAVE_PARALLEL + +#define H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC 0x00D0A02 + +typedef struct H5AC2_slist_entry_t +{ + uint32_t magic; + + haddr_t addr; +} H5AC2_slist_entry_t; + +/* Declare a free list to manage the H5AC2_slist_entry_t struct */ +H5FL_DEFINE_STATIC(H5AC2_slist_entry_t); + +#endif /* H5_HAVE_PARALLEL */ + + +/* + * Private file-scope variables. + */ + +/* Default dataset transfer property list for metadata I/O calls */ +/* (Collective set, "block before metadata write" set and "library internal" set) */ +/* (Global variable definition, declaration is in H5AC2private.h also) */ +hid_t H5AC2_dxpl_id=(-1); + +/* Private dataset transfer property list for metadata I/O calls */ +/* (Collective set and "library internal" set) */ +/* (Static variable definition) */ +static hid_t H5AC2_noblock_dxpl_id=(-1); + +/* Dataset transfer property list for independent metadata I/O calls */ +/* (just "library internal" set - i.e. independent transfer mode) */ +/* (Global variable definition, declaration is in H5AC2private.h also) */ +hid_t H5AC2_ind_dxpl_id=(-1); + + +/* + * Private file-scope function declarations: + */ + +static herr_t H5AC2_check_if_write_permitted(const H5F_t *f, + hid_t dxpl_id, + hbool_t * write_permitted_ptr); + +#ifdef H5_HAVE_PARALLEL +static herr_t H5AC2_broadcast_clean_list(H5AC2_t * cache_ptr); +#endif /* JRM */ + +static herr_t H5AC2_ext_config_2_int_config( + H5AC2_cache_config_t * ext_conf_ptr, + H5C2_auto_size_ctl_t * int_conf_ptr); + +#ifdef H5_HAVE_PARALLEL +static herr_t H5AC2_log_deleted_entry(H5AC2_t * cache_ptr, + H5AC2_info_t * entry_ptr, + haddr_t addr, + unsigned int flags); + +static herr_t H5AC2_log_dirtied_entry(H5AC2_t * cache_ptr, + H5C2_cache_entry_t * entry_ptr, + haddr_t addr, + hbool_t size_changed, + size_t new_size); + +static herr_t H5AC2_log_flushed_entry(H5C2_t * cache_ptr, + haddr_t addr, + hbool_t was_dirty, + unsigned flags, + int type_id); + +#if 0 /* this is useful debugging code -- JRM */ +static herr_t H5AC2_log_flushed_entry_dummy(H5C2_t * cache_ptr, + haddr_t addr, + hbool_t was_dirty, + unsigned flags, + int type_id); +#endif /* JRM */ + +static herr_t H5AC2_log_inserted_entry(H5F_t * f, + H5AC2_t * cache_ptr, + H5AC2_info_t * entry_ptr, + const H5AC2_class_t * type, + haddr_t addr, + size_t size); + +static herr_t H5AC2_propagate_flushed_and_still_clean_entries_list(H5F_t * f, + hid_t dxpl_id, + H5AC2_t * cache_ptr, + hbool_t do_barrier); + +static herr_t H5AC2_receive_and_apply_clean_list(H5F_t * f, + hid_t dxpl_id, + H5AC2_t * cache_ptr); + +static herr_t H5AC2_log_renamed_entry(H5AC2_t * cache_ptr, + haddr_t old_addr, + haddr_t new_addr); +#endif /* H5_HAVE_PARALLEL */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_init + * + * Purpose: Initialize the interface from some other layer. + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Quincey Koziol + * Saturday, January 18, 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5AC2_init(void) +{ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5AC2_init, FAIL) + /* FUNC_ENTER() does all the work */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5AC2_init_interface + * + * Purpose: Initialize interface-specific information + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, July 18, 2002 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5AC2_init_interface(void) +{ +#ifdef H5_HAVE_PARALLEL + H5P_genclass_t *xfer_pclass; /* Dataset transfer property list class object */ + H5P_genplist_t *xfer_plist; /* Dataset transfer property list object */ + unsigned block_before_meta_write; /* "block before meta write" property value */ + unsigned library_internal=1; /* "library internal" property value */ + H5FD_mpio_xfer_t xfer_mode; /* I/O transfer mode property value */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5AC2_init_interface) + + /* Sanity check */ + HDassert(H5P_CLS_DATASET_XFER_g!=(-1)); + + /* Get the dataset transfer property list class object */ + if (NULL == (xfer_pclass = H5I_object(H5P_CLS_DATASET_XFER_g))) + HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get property list class") + + /* Get an ID for the blocking, collective H5AC2 dxpl */ + if ((H5AC2_dxpl_id=H5P_create_id(xfer_pclass)) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "unable to register property list") + + /* Get the property list object */ + if (NULL == (xfer_plist = H5I_object(H5AC2_dxpl_id))) + HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get new property list object") + + /* Insert 'block before metadata write' property */ + block_before_meta_write=1; + if(H5P_insert(xfer_plist,H5AC2_BLOCK_BEFORE_META_WRITE_NAME,H5AC2_BLOCK_BEFORE_META_WRITE_SIZE,&block_before_meta_write,NULL,NULL,NULL,NULL,NULL,NULL)<0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property") + + /* Insert 'library internal' property */ + if(H5P_insert(xfer_plist,H5AC2_LIBRARY_INTERNAL_NAME,H5AC2_LIBRARY_INTERNAL_SIZE,&library_internal,NULL,NULL,NULL,NULL,NULL,NULL)<0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property") + + /* Set the transfer mode */ + xfer_mode=H5FD_MPIO_COLLECTIVE; + if (H5P_set(xfer_plist,H5D_XFER_IO_XFER_MODE_NAME,&xfer_mode)<0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value") + + /* Get an ID for the non-blocking, collective H5AC2 dxpl */ + if ((H5AC2_noblock_dxpl_id=H5P_create_id(xfer_pclass)) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "unable to register property list") + + /* Get the property list object */ + if (NULL == (xfer_plist = H5I_object(H5AC2_noblock_dxpl_id))) + HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get new property list object") + + /* Insert 'block before metadata write' property */ + block_before_meta_write=0; + if(H5P_insert(xfer_plist,H5AC2_BLOCK_BEFORE_META_WRITE_NAME,H5AC2_BLOCK_BEFORE_META_WRITE_SIZE,&block_before_meta_write,NULL,NULL,NULL,NULL,NULL,NULL)<0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property") + + /* Insert 'library internal' property */ + if(H5P_insert(xfer_plist,H5AC2_LIBRARY_INTERNAL_NAME,H5AC2_LIBRARY_INTERNAL_SIZE,&library_internal,NULL,NULL,NULL,NULL,NULL,NULL)<0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property") + + /* Set the transfer mode */ + xfer_mode=H5FD_MPIO_COLLECTIVE; + if (H5P_set(xfer_plist,H5D_XFER_IO_XFER_MODE_NAME,&xfer_mode)<0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value") + + /* Get an ID for the non-blocking, independent H5AC2 dxpl */ + if ((H5AC2_ind_dxpl_id=H5P_create_id(xfer_pclass)) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "unable to register property list") + + /* Get the property list object */ + if (NULL == (xfer_plist = H5I_object(H5AC2_ind_dxpl_id))) + HGOTO_ERROR(H5E_CACHE, H5E_BADATOM, FAIL, "can't get new property list object") + + /* Insert 'block before metadata write' property */ + block_before_meta_write=0; + if(H5P_insert(xfer_plist,H5AC2_BLOCK_BEFORE_META_WRITE_NAME,H5AC2_BLOCK_BEFORE_META_WRITE_SIZE,&block_before_meta_write,NULL,NULL,NULL,NULL,NULL,NULL)<0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property") + + /* Insert 'library internal' property */ + if(H5P_insert(xfer_plist,H5AC2_LIBRARY_INTERNAL_NAME,H5AC2_LIBRARY_INTERNAL_SIZE,&library_internal,NULL,NULL,NULL,NULL,NULL,NULL)<0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't insert metadata cache dxpl property") + + /* Set the transfer mode */ + xfer_mode=H5FD_MPIO_INDEPENDENT; + if (H5P_set(xfer_plist,H5D_XFER_IO_XFER_MODE_NAME,&xfer_mode)<0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value") + +done: + FUNC_LEAVE_NOAPI(ret_value) + +#else /* H5_HAVE_PARALLEL */ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5AC2_init_interface) + + /* Sanity check */ + assert(H5P_LST_DATASET_XFER_g!=(-1)); + + H5AC2_dxpl_id=H5P_DATASET_XFER_DEFAULT; + H5AC2_noblock_dxpl_id=H5P_DATASET_XFER_DEFAULT; + H5AC2_ind_dxpl_id=H5P_DATASET_XFER_DEFAULT; + + FUNC_LEAVE_NOAPI(SUCCEED) +#endif /* H5_HAVE_PARALLEL */ +} /* end H5AC2_init_interface() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_term_interface + * + * Purpose: Terminate this interface. + * + * Return: Success: Positive if anything was done that might + * affect other interfaces; zero otherwise. + * + * Failure: Negative. + * + * Programmer: Quincey Koziol + * Thursday, July 18, 2002 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +H5AC2_term_interface(void) +{ + int n=0; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5AC2_term_interface) + + if (H5_interface_initialize_g) { +#ifdef H5_HAVE_PARALLEL + if(H5AC2_dxpl_id>0 || H5AC2_noblock_dxpl_id>0 || H5AC2_ind_dxpl_id>0) { + /* Indicate more work to do */ + n = 1; /* H5I */ + + /* Close H5AC2 dxpl */ + if (H5I_dec_ref(H5AC2_dxpl_id) < 0 || + H5I_dec_ref(H5AC2_noblock_dxpl_id) < 0 || + H5I_dec_ref(H5AC2_ind_dxpl_id) < 0) + H5E_clear_stack(NULL); /*ignore error*/ + else { + /* Reset static IDs */ + H5AC2_dxpl_id=(-1); + H5AC2_noblock_dxpl_id=(-1); + H5AC2_ind_dxpl_id=(-1); + + /* Reset interface initialization flag */ + H5_interface_initialize_g = 0; + } /* end else */ + } /* end if */ + else +#else /* H5_HAVE_PARALLEL */ + /* Reset static IDs */ + H5AC2_dxpl_id=(-1); + H5AC2_noblock_dxpl_id=(-1); + H5AC2_ind_dxpl_id=(-1); + +#endif /* H5_HAVE_PARALLEL */ + /* Reset interface initialization flag */ + H5_interface_initialize_g = 0; + } /* end if */ + + FUNC_LEAVE_NOAPI(n) +} /* end H5AC2_term_interface() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_create + * + * Purpose: Initialize the cache just after a file is opened. The + * SIZE_HINT is the number of cache slots desired. If you + * pass an invalid value then H5AC2_NSLOTS is used. You can + * turn off caching by using 1 for the SIZE_HINT value. + * + * Return: Success: Number of slots actually used. + * + * Failure: Negative + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Jul 9 1997 + * + * Modifications: + * + * Complete re-design and re-write to support the re-designed + * metadata cache. + * + * At present, the size_hint is ignored, and the + * max_cache_size and min_clean_size fields are hard + * coded. This should be fixed, but a parameter + * list change will be required, so I will leave it + * for now. + * + * Since no-one seems to care, the function now returns + * one on success. + * JRM - 4/28/04 + * + * Reworked the function again after abstracting its guts to + * the similar function in H5C2.c. The function is now a + * wrapper for H5C2_create(). + * JRM - 6/4/04 + * + * Deleted the old size_hint parameter and added the + * max_cache_size, and min_clean_size parameters. + * + * JRM - 3/10/05 + * + * Deleted the max_cache_size, and min_clean_size parameters, + * and added the config_ptr parameter. Added code to + * validate the resize configuration before we do anything. + * + * JRM - 3/24/05 + * + * Changed the type of config_ptr from H5AC2_auto_size_ctl_t * + * to H5AC2_cache_config_t *. Propagated associated changes + * through the function. + * JRM - 4/7/05 + * + * Added code allocating and initializing the auxilary + * structure (an instance of H5AC2_aux_t), and linking it + * to the instance of H5C2_t created by H5C2_create(). At + * present, the auxilary structure is only used in PHDF5. + * + * JRM - 6/28/05 + * + * Added code to set the prefix if required. + * + * JRM - 1/20/06 + * + * Added code to initialize the new write_done field. + * + * JRM - 5/11/06 + * + * Reworked code to conform with changes in the cache + * API. + * JRM - 10/18/07 + * + *------------------------------------------------------------------------- + */ + +static const char * H5AC2_entry_type_names[H5AC2_NTYPES] = +{ + "B-tree nodes", + "symbol table nodes", + "local heaps", + "global heaps", + "object headers", + "v2 B-tree headers", + "v2 B-tree internal nodes", + "v2 B-tree leaf nodes", + "fractal heap headers", + "fractal heap direct blocks", + "fractal heap indirect blocks", + "free space headers", + "free space sections", + "shared OH message master table", + "shared OH message index", + "test entry" /* for testing only -- not used for actual files */ +}; + +herr_t +H5AC2_create(const H5F_t *f, + H5AC2_cache_config_t *config_ptr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + herr_t result; +#ifdef H5_HAVE_PARALLEL + char prefix[H5C2__PREFIX_LEN] = ""; + MPI_Comm mpi_comm = MPI_COMM_NULL; + int mpi_rank = -1; + int mpi_size = -1; + H5AC2_aux_t * aux_ptr = NULL; +#endif /* H5_HAVE_PARALLEL */ + + FUNC_ENTER_NOAPI(H5AC2_create, FAIL) + + HDassert ( f ); + HDassert ( NULL == f->shared->cache2 ); + HDassert ( config_ptr != NULL ) ; + HDassert ( NELMTS(H5AC2_entry_type_names) == H5AC2_NTYPES); + HDassert ( H5C2__MAX_NUM_TYPE_IDS == H5AC2_NTYPES); + + result = H5AC2_validate_config(config_ptr); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Bad cache configuration"); + } + +#ifdef H5_HAVE_PARALLEL + if ( IS_H5FD_MPI(f) ) { + + if ( (mpi_comm = H5F_mpi_get_comm(f)) == MPI_COMM_NULL ) { + + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, \ + "can't get MPI communicator") + } + + if ( (mpi_rank = H5F_mpi_get_rank(f)) < 0 ) { + + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get mpi rank") + } + + if ( (mpi_size = H5F_mpi_get_size(f)) < 0 ) { + + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get mpi size") + } + + /* There is no point in setting up the auxilary structure if size + * is less than or equal to 1, as there will never be any processes + * to broadcast the clean lists to. + */ + if ( mpi_size > 1 ) { + + if ( NULL == (aux_ptr = H5FL_CALLOC(H5AC2_aux_t)) ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "Can't allocate H5AC2 auxilary structure.") + + } else { + + aux_ptr->magic = H5AC2__H5AC2_AUX_T_MAGIC; + aux_ptr->mpi_comm = mpi_comm; + aux_ptr->mpi_rank = mpi_rank; + aux_ptr->mpi_size = mpi_size; + aux_ptr->write_permitted = FALSE; + aux_ptr->dirty_bytes_threshold = + H5AC2__DEFAULT_DIRTY_BYTES_THRESHOLD; + aux_ptr->dirty_bytes = 0; +#if H5AC2_DEBUG_DIRTY_BYTES_CREATION + aux_ptr->dirty_bytes_propagations = 0; + aux_ptr->unprotect_dirty_bytes = 0; + aux_ptr->unprotect_dirty_bytes_updates = 0; + aux_ptr->insert_dirty_bytes = 0; + aux_ptr->insert_dirty_bytes_updates = 0; + aux_ptr->rename_dirty_bytes = 0; + aux_ptr->rename_dirty_bytes_updates = 0; +#endif /* H5AC2_DEBUG_DIRTY_BYTES_CREATION */ + aux_ptr->d_slist_ptr = NULL; + aux_ptr->d_slist_len = 0; + aux_ptr->c_slist_ptr = NULL; + aux_ptr->c_slist_len = 0; + aux_ptr->write_done = NULL; + + sprintf(prefix, "%d:", mpi_rank); + } + + if ( mpi_rank == 0 ) { + + aux_ptr->d_slist_ptr = + H5SL_create(H5SL_TYPE_HADDR,0.5,(size_t)16); + + if ( aux_ptr->d_slist_ptr == NULL ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, + "can't create dirtied entry list.") + } + + aux_ptr->c_slist_ptr = + H5SL_create(H5SL_TYPE_HADDR,0.5,(size_t)16); + + if ( aux_ptr->c_slist_ptr == NULL ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, + "can't create cleaned entry list.") + } + } + } + + if ( aux_ptr != NULL ) { + + if ( aux_ptr->mpi_rank == 0 ) { + + f->shared->cache2 = H5C2_create(f, + H5AC2__DEFAULT_MAX_CACHE_SIZE, + H5AC2__DEFAULT_MIN_CLEAN_SIZE, + (H5AC2_NTYPES - 1), + (const char **)H5AC2_entry_type_names, + H5AC2_check_if_write_permitted, + TRUE, + H5AC2_log_flushed_entry, + (void *)aux_ptr); + + } else { + + f->shared->cache2 = H5C2_create(f, + H5AC2__DEFAULT_MAX_CACHE_SIZE, + H5AC2__DEFAULT_MIN_CLEAN_SIZE, + (H5AC2_NTYPES - 1), + (const char **)H5AC2_entry_type_names, + NULL, + FALSE, +#if 0 /* this is useful debugging code -- keep it for a while */ /* JRM */ + H5AC2_log_flushed_entry_dummy, +#else /* JRM */ + NULL, +#endif /* JRM */ + (void *)aux_ptr); + } + + } else { + + f->shared->cache2 = H5C2_create(f, + H5AC2__DEFAULT_MAX_CACHE_SIZE, + H5AC2__DEFAULT_MIN_CLEAN_SIZE, + (H5AC2_NTYPES - 1), + (const char **)H5AC2_entry_type_names, + H5AC2_check_if_write_permitted, + TRUE, + NULL, + NULL); + } + } else { +#endif /* H5_HAVE_PARALLEL */ + /* The default max cache size and min clean size will frequently be + * overwritten shortly by the subsequent set resize config call. + * -- JRM + */ + + f->shared->cache2 = H5C2_create(f, + H5AC2__DEFAULT_MAX_CACHE_SIZE, + H5AC2__DEFAULT_MIN_CLEAN_SIZE, + (H5AC2_NTYPES - 1), + (const char **)H5AC2_entry_type_names, + H5AC2_check_if_write_permitted, + TRUE, + NULL, + NULL); +#ifdef H5_HAVE_PARALLEL + } +#endif /* H5_HAVE_PARALLEL */ + + if ( NULL == f->shared->cache2 ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + } +#ifdef H5_HAVE_PARALLEL + else if ( aux_ptr != NULL ) { + + result = H5C2_set_prefix(f->shared->cache2, prefix); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "H5C2_set_prefix() failed") + } + } +#endif /* H5_HAVE_PARALLEL */ + + result = H5AC2_set_cache_auto_resize_config(f->shared->cache2, config_ptr); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "auto resize configuration failed") + } + +done: + +#ifdef H5_HAVE_PARALLEL + + /* if there is a failure, try to tidy up the auxilary structure */ + + if ( ret_value != SUCCEED ) { + + if ( aux_ptr != NULL ) { + + if ( aux_ptr->d_slist_ptr != NULL ) { + + H5SL_close(aux_ptr->d_slist_ptr); + } + + if ( aux_ptr->c_slist_ptr != NULL ) { + + H5SL_close(aux_ptr->c_slist_ptr); + } + + aux_ptr->magic = 0; + H5FL_FREE(H5AC2_aux_t, aux_ptr); + aux_ptr = NULL; + } + } +#endif /* H5_HAVE_PARALLEL */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_create() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_dest + * + * Purpose: Flushes all data to disk and destroys the cache. + * This function fails if any object are protected since the + * resulting file might not be consistent. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Jul 9 1997 + * + * Modifications: + * + * Complete re-design and re-write to support the re-designed + * metadata cache. + * JRM - 5/12/04 + * + * Abstracted the guts of the function to H5C_dest() in H5C.c, + * and then re-wrote the function as a wrapper for H5C_dest(). + * + * JRM - 6/7/04 + * + * Added code to free the auxiliary structure and its + * associated slist if present. + * JRM - 6/28/05 + * + * Added code to close the trace file if it is present. + * + * JRM - 6/8/06 + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ +herr_t +H5AC2_dest(H5F_t *f, hid_t dxpl_id) +{ + H5AC2_t *cache = NULL; + herr_t ret_value=SUCCEED; /* Return value */ +#ifdef H5_HAVE_PARALLEL + H5AC2_aux_t * aux_ptr = NULL; +#endif /* H5_HAVE_PARALLEL */ + + FUNC_ENTER_NOAPI(H5AC2_dest, FAIL) + + assert(f); + assert(f->shared->cache2); + cache = f->shared->cache2; +#ifdef H5_HAVE_PARALLEL + aux_ptr = cache->aux_ptr; + + if ( aux_ptr != NULL ) { + + HDassert ( aux_ptr->magic == H5AC2__H5AC2_AUX_T_MAGIC ); + } +#endif /* H5_HAVE_PARALLEL */ + +#if H5AC2__TRACE_FILE_ENABLED + if ( H5AC2_close_trace_file(cache) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5AC2_close_trace_file() failed.") + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + if ( H5C2_dest(cache, dxpl_id) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFREE, FAIL, "can't destroy cache") + } + + f->shared->cache2 = NULL; + +#ifdef H5_HAVE_PARALLEL + if ( aux_ptr != NULL ) { + + if ( aux_ptr->d_slist_ptr != NULL ) { + + H5SL_close(aux_ptr->d_slist_ptr); + } + + if ( aux_ptr->c_slist_ptr != NULL ) { + + H5SL_close(aux_ptr->c_slist_ptr); + } + + aux_ptr->magic = 0; + H5FL_FREE(H5AC2_aux_t, aux_ptr); + aux_ptr = NULL; + } +#endif /* H5_HAVE_PARALLEL */ + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_dest() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_expunge_entry + * + * Purpose: Expunge the target entry from the cache without writing it + * to disk even if it is dirty. The entry must not be either + * pinned or protected. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 6/30/06 + * + * Modifications: + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ +herr_t +H5AC2_expunge_entry(H5F_t *f, + hid_t dxpl_id, + const H5AC2_class_t *type, + haddr_t addr) +{ + herr_t result; + herr_t ret_value=SUCCEED; /* Return value */ + H5AC2_t * cache_ptr = NULL; +#if H5AC2__TRACE_FILE_ENABLED + char trace[128] = ""; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_ENTER_NOAPI(H5AC2_expunge_entry, FAIL) + + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->cache2); + HDassert(type); + HDassert(H5F_addr_defined(addr)); + + cache_ptr = f->shared->cache2; + +#if H5AC2__TRACE_FILE_ENABLED + /* For the expunge entry call, only the addr, and type id are really + * necessary in the trace file. Write the return value to catch occult + * errors. + */ + if ( ( cache_ptr != NULL ) && + ( H5C2_get_trace_file_ptr(cache_ptr, &trace_file_ptr) >= 0 ) && + ( trace_file_ptr != NULL ) ) { + + sprintf(trace, "H5AC2_expunge_entry 0x%lx %d", + (unsigned long)addr, + (int)(type->id)); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + result = H5C2_expunge_entry(cache_ptr, + dxpl_id, + type, + addr); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, \ + "H5C2_expunge_entry() failed.") + } + +done: + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_expunge_entry() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_flush + * + * Purpose: Flush (and possibly destroy) the metadata cache associated + * with the specified file. + * + * This is a re-write of an earlier version of the function + * which was reputedly capable of flushing (and destroying + * if requested) individual entries, individual entries if + * they match the supplied type, all entries of a given type, + * as well as all entries in the cache. + * + * As only this last capability is actually used at present, + * I have not implemented the other capabilities in this + * version of the function. + * + * The type and addr parameters are retained to avoid source + * code changed, but values other than NULL and HADDR_UNDEF + * respectively are errors. If all goes well, they should + * be removed, and the function renamed to something more + * descriptive -- perhaps H5AC2_flush_cache. + * + * If the cache contains protected entries, the function will + * fail, as protected entries cannot be flushed. However + * all unprotected entries should be flushed before the + * function returns failure. + * + * For historical purposes, the original version of the + * purpose section is reproduced below: + * + * ============ Original Version of "Purpose:" ============ + * + * Flushes (and destroys if DESTROY is non-zero) the specified + * entry from the cache. If the entry TYPE is CACHE_FREE and + * ADDR is HADDR_UNDEF then all types of entries are + * flushed. If TYPE is CACHE_FREE and ADDR is defined then + * whatever is cached at ADDR is flushed. Otherwise the thing + * at ADDR is flushed if it is the correct type. + * + * If there are protected objects they will not be flushed. + * However, an attempt will be made to flush all non-protected + * items before this function returns failure. + * + * Return: Non-negative on success/Negative on failure if there was a + * request to flush all items and something was protected. + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Jul 9 1997 + * + * Modifications: + * Robb Matzke, 1999-07-27 + * The ADDR argument is passed by value. + * + * Complete re-write. See above for details. -- JRM 5/11/04 + * + * Abstracted the guts of the function to H5C_flush_cache() + * in H5C.c, and then re-wrote the function as a wrapper for + * H5C_flush_cache(). + * + * JRM - 6/7/04 + * + * JRM - 7/5/05 + * Modified function as part of a fix for a cache coherency + * bug in PHDF5. See the header comments on the H5AC2_aux_t + * structure for details. + * + * JRM -- 5/11/06 + * Added call to the write_done callback. + * + * JRM -- 6/6/06 + * Added trace file support. + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ +herr_t +H5AC2_flush(H5F_t *f, hid_t dxpl_id, unsigned flags) +{ + herr_t status; + herr_t ret_value = SUCCEED; /* Return value */ +#ifdef H5_HAVE_PARALLEL + H5AC2_aux_t * aux_ptr = NULL; + int mpi_code; +#endif /* H5_HAVE_PARALLEL */ +#if H5AC2__TRACE_FILE_ENABLED + char trace[128] = ""; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + + FUNC_ENTER_NOAPI(H5AC2_flush, FAIL) + + HDassert(f); + HDassert(f->shared->cache2); + +#if H5AC2__TRACE_FILE_ENABLED + /* For the flush, only the flags are really necessary in the trace file. + * Write the result to catch occult errors. + */ + if ( ( f != NULL ) && + ( f->shared != NULL ) && + ( f->shared->cache2 != NULL ) && + ( H5C2_get_trace_file_ptr(f->shared->cache2, &trace_file_ptr) >= 0) && + ( trace_file_ptr != NULL ) ) { + + sprintf(trace, "H5AC2_flush 0x%x", flags); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + +#ifdef H5_HAVE_PARALLEL + aux_ptr = f->shared->cache2->aux_ptr; + + if ( aux_ptr != NULL ) { + +#if H5AC2_DEBUG_DIRTY_BYTES_CREATION + HDfprintf(stdout, + "%d::H5AC2_flush: (u/uu/i/iu/r/ru) = %d/%d/%d/%d/%d/%d\n", + (int)(aux_ptr->mpi_rank), + (int)(aux_ptr->unprotect_dirty_bytes), + (int)(aux_ptr->unprotect_dirty_bytes_updates), + (int)(aux_ptr->insert_dirty_bytes), + (int)(aux_ptr->insert_dirty_bytes_updates), + (int)(aux_ptr->rename_dirty_bytes), + (int)(aux_ptr->rename_dirty_bytes_updates)); +#endif /* H5AC2_DEBUG_DIRTY_BYTES_CREATION */ + + /* to prevent "messages from the future" we must synchronize all + * processes before we start the flush. Hence the following + * barrier. + */ + if ( MPI_SUCCESS != (mpi_code = MPI_Barrier(aux_ptr->mpi_comm)) ) { + + HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_code) + } + + /* if the clear only flag is set, this flush will not involve any + * disk I/O. In such cases, it is not necessary to let process 0 + * flush first. + */ + if ( ( aux_ptr->mpi_rank == 0 ) && + ( (flags & H5AC2__FLUSH_CLEAR_ONLY_FLAG) == 0 ) ) { + + unsigned init_flush_flags = H5AC2__NO_FLAGS_SET; + + if ( ( (flags & H5AC2__FLUSH_MARKED_ENTRIES_FLAG) != 0 ) && + ( (flags & H5AC2__FLUSH_INVALIDATE_FLAG) == 0 ) ) { + + init_flush_flags |= H5AC2__FLUSH_MARKED_ENTRIES_FLAG; + } + + aux_ptr->write_permitted = TRUE; + + status = H5C2_flush_cache(f->shared->cache2, + dxpl_id, + init_flush_flags); + + aux_ptr->write_permitted = FALSE; + + if ( status < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush.") + } + + if ( aux_ptr->write_done != NULL ) { + + (aux_ptr->write_done)(); + } + + } /* end if ( aux_ptr->mpi_rank == 0 ) */ + + status = H5AC2_propagate_flushed_and_still_clean_entries_list(f, + H5AC2_noblock_dxpl_id, + f->shared->cache2, + FALSE); + } /* end if ( aux_ptr != NULL ) */ +#endif /* H5_HAVE_PARALLEL */ + + status = H5C2_flush_cache(f->shared->cache2, + dxpl_id, + flags); + + if ( status < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Can't flush entry.") + } + +done: + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_flush() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_get_entry_status + * + * Purpose: Given a file address, determine whether the metadata + * cache contains an entry at that location. If it does, + * also determine whether the entry is dirty, protected, + * pinned, etc. and return that information to the caller + * in *status_ptr. + * + * If the specified entry doesn't exist, set *status_ptr + * to zero. + * + * On error, the value of *status_ptr is undefined. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 4/27/06 + * + * Modifications: + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ + +herr_t +H5AC2_get_entry_status(H5F_t * f, + haddr_t addr, + unsigned * status_ptr) +{ + H5C2_t *cache_ptr = f->shared->cache2; + herr_t ret_value = SUCCEED; /* Return value */ + herr_t result; + hbool_t in_cache; + hbool_t is_dirty; + hbool_t is_protected; + hbool_t is_pinned; + size_t entry_size; + unsigned status = 0; + + FUNC_ENTER_NOAPI(H5AC2_get_entry_status, FAIL) + + if ( ( cache_ptr == NULL ) || + ( cache_ptr->magic != H5C2__H5C2_T_MAGIC ) || + ( ! H5F_addr_defined(addr) ) || + ( status_ptr == NULL ) ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad param(s) on entry.") + } + + result = H5C2_get_entry_status(cache_ptr, addr, &entry_size, &in_cache, + &is_dirty, &is_protected, &is_pinned); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_get_entry_status() failed.") + } + + if ( in_cache ) { + + status |= H5AC2_ES__IN_CACHE; + + if ( is_dirty ) + status |= H5AC2_ES__IS_DIRTY; + + if ( is_protected ) + status |= H5AC2_ES__IS_PROTECTED; + + if ( is_pinned ) + status |= H5AC2_ES__IS_PINNED; + } + + *status_ptr = status; + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_get_entry_status() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_set + * + * Purpose: Adds the specified thing to the cache. The thing need not + * exist on disk yet, but it must have an address and disk + * space reserved. + * + * If H5AC2_DEBUG is defined then this function checks + * that the object being inserted isn't a protected object. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Jul 9 1997 + * + * Modifications: + * Robb Matzke, 1999-07-27 + * The ADDR argument is passed by value. + * + * Bill Wendling, 2003-09-16 + * Added automatic "flush" if the FPHDF5 driver is being + * used. This'll write the metadata to the SAP where other, + * lesser processes can grab it. + * + * JRM - 5/13/04 + * Complete re-write for the new metadata cache. The new + * code is functionally almost identical to the old, although + * the sanity check for a protected entry is now an assert + * at the beginning of the function. + * + * JRM - 6/7/04 + * Abstracted the guts of the function to H5C_insert_entry() + * in H5C.c, and then re-wrote the function as a wrapper for + * H5C_insert_entry(). + * + * JRM - 1/6/05 + * Added the flags parameter. At present, this parameter is + * only used to set the new flush_marker field on the new + * entry. Since this doesn't apply to the SAP code, no change + * is needed there. Thus the only change to the body of the + * code is to pass the flags parameter through to + * H5C_insert_entry(). + * + * JRM - 6/6/05 + * Added code to force newly inserted entries to be dirty + * in the flexible parallel case. The normal case is handled + * in H5C.c. This is part of a series of changes directed at + * moving management of the dirty flag on cache entries into + * the cache code. + * + * JRM - 7/5/05 + * Added code to track dirty byte generation, and to trigger + * clean entry list propagation when it exceeds a user + * specified threshold. Note that this code only applies in + * the PHDF5 case. It should have no effect on either the + * serial or FPHSD5 cases. + * + * JRM - 6/6/06 + * Added trace file support. + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ + +herr_t +H5AC2_set(H5F_t *f, hid_t dxpl_id, const H5AC2_class_t *type, haddr_t addr, size_t len, void *thing, unsigned int flags) +{ + herr_t result; + H5AC2_info_t *info; + H5AC2_t *cache; + herr_t ret_value=SUCCEED; /* Return value */ +#ifdef H5_HAVE_PARALLEL + H5AC2_aux_t * aux_ptr = NULL; +#endif /* H5_HAVE_PARALLEL */ +#if H5AC2__TRACE_FILE_ENABLED + char trace[128] = ""; + size_t trace_entry_size = 0; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_ENTER_NOAPI(H5AC2_set, FAIL) + + HDassert(f); + HDassert(f->shared->cache2); + HDassert(type); + HDassert(type->serialize); + HDassert(H5F_addr_defined(addr)); + HDassert(thing); + +#if H5AC2__TRACE_FILE_ENABLED + /* For the insert, only the addr, size, type id and flags are really + * necessary in the trace file. Write the result to catch occult + * errors. + * + * Note that some data is not available right now -- put what we can + * in the trace buffer now, and fill in the rest at the end. + */ + if ( ( f != NULL ) && + ( f->shared != NULL ) && + ( f->shared->cache2 != NULL ) && + ( H5C2_get_trace_file_ptr(f->shared->cache2, &trace_file_ptr) >= 0) && + ( trace_file_ptr != NULL ) ) { + + sprintf(trace, "H5AC2_set 0x%lx %ld %d 0x%x", + (unsigned long)addr, + (long)len, + type->id, + flags); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + /* Get local copy of this information */ + cache = f->shared->cache2; + info = (H5AC2_info_t *)thing; + + info->addr = addr; + info->type = type; + info->is_protected = FALSE; + +#ifdef H5_HAVE_PARALLEL + if ( NULL != (aux_ptr = f->shared->cache2->aux_ptr) ) { + + result = H5AC2_log_inserted_entry(f, + f->shared->cache2, + (H5AC2_info_t *)thing, + type, + addr, + len); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, \ + "H5AC2_log_inserted_entry() failed.") + } + } +#endif /* H5_HAVE_PARALLEL */ + + result = H5C2_insert_entry(cache, + dxpl_id, + type, + addr, + len, + thing, + flags); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "H5C2_insert_entry() failed") + } + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + /* make note of the entry size */ + trace_entry_size = ((H5C2_cache_entry_t *)thing)->size; + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + +#ifdef H5_HAVE_PARALLEL + if ( ( aux_ptr != NULL ) && + ( aux_ptr->dirty_bytes >= aux_ptr->dirty_bytes_threshold ) ) { + + result = H5AC2_propagate_flushed_and_still_clean_entries_list(f, + H5AC2_noblock_dxpl_id, + f->shared->cache2, + TRUE); + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "Can't propagate clean entries list.") + } + } +#endif /* H5_HAVE_PARALLEL */ + +done: + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + HDfprintf(trace_file_ptr, "%s %d %d\n", trace, + (int)trace_entry_size, + (int)ret_value); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_set() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_mark_pinned_entry_dirty + * + * Purpose: Mark a pinned entry as dirty. The target entry MUST be + * be pinned, and MUST be unprotected. + * + * If the entry has changed size, the function updates + * data structures for the size change. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 4/11/06 + * + * Modifications: + * + * Added trace file support. JRM -- 6/6/06 + * + * Modified code in support of revised cache API needed + * to permit journaling. JRM -- 10/18/07 + * + *------------------------------------------------------------------------- + */ +herr_t +H5AC2_mark_pinned_entry_dirty(H5F_t * f, + void * thing, + hbool_t size_changed, + size_t new_size) +{ + H5C2_t *cache_ptr = f->shared->cache2; + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ +#if H5AC2__TRACE_FILE_ENABLED + char trace[128] = ""; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_ENTER_NOAPI(H5AC2_mark_pinned_entry_dirty, FAIL) + +#if H5AC2__TRACE_FILE_ENABLED + /* For the mark pinned entry dirty call, only the addr, size_changed, + * and new_size are really necessary in the trace file. Write the result + * to catch occult errors. + */ + if ( ( f != NULL ) && + ( f->shared != NULL ) && + ( f->shared->cache2 != NULL ) && + ( H5C2_get_trace_file_ptr(f->shared->cache2, &trace_file_ptr) >= 0) && + ( trace_file_ptr != NULL ) ) { + + sprintf(trace, "H5AC2_mark_pinned_entry_dirty 0x%lx %d %d", + (unsigned long)(((H5C2_cache_entry_t *)thing)->addr), + (int)size_changed, + (int)new_size); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + +#ifdef H5_HAVE_PARALLEL + + HDassert( cache_ptr ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( thing ); + + if ( ( ((H5AC2_info_t *)thing)->is_dirty == FALSE ) && + ( NULL != cache_ptr->aux_ptr) ) { + + H5AC2_info_t * entry_ptr; + + HDassert( ( size_changed == TRUE ) || ( size_changed == FALSE ) ); + + entry_ptr = (H5AC2_info_t *)thing; + + if ( ! ( entry_ptr->is_pinned ) ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, \ + "Entry isn't pinned??") + } + + if ( entry_ptr->is_protected ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, \ + "Entry is protected??") + } + + result = H5AC2_log_dirtied_entry(cache_ptr, + entry_ptr, + entry_ptr->addr, + size_changed, + new_size); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, \ + "H5AC2_log_dirtied_entry() failed.") + } + } +#endif /* H5_HAVE_PARALLEL */ + + result = H5C2_mark_pinned_entry_dirty(cache_ptr, + thing, + size_changed, + new_size); + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, \ + "H5C2_mark_pinned_entry_dirty() failed.") + + } + +done: + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_mark_pinned_entry_dirty() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_mark_pinned_or_protected_entry_dirty + * + * Purpose: Mark a pinned or protected entry as dirty. The target + * entry MUST be either pinned, protected, or both. + * + * Unlike H5AC2_mark_pinned_entry_dirty(), this function does + * not support size changes. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 5/16/06 + * + * Modifications: + * + * Added trace file support. JRM -- 6/6/06 + * + * Modified code in support of revised cache API needed + * to permit journaling. JRM -- 10/18/07 + * + *------------------------------------------------------------------------- + */ +herr_t +H5AC2_mark_pinned_or_protected_entry_dirty(H5F_t * f, + void * thing) +{ + H5C2_t * cache_ptr = f->shared->cache2; +#ifdef H5_HAVE_PARALLEL + H5AC2_info_t * info_ptr; +#endif /* H5_HAVE_PARALLEL */ + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ +#if H5AC2__TRACE_FILE_ENABLED + char trace[128] = ""; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_ENTER_NOAPI(H5AC2_mark_pinned_or_protected_entry_dirty, FAIL) + +#if H5AC2__TRACE_FILE_ENABLED + /* For the mark pinned or protected entry dirty call, only the addr + * is really necessary in the trace file. Write the result to catch + * occult errors. + */ + if ( ( f != NULL ) && + ( f->shared != NULL ) && + ( f->shared->cache2 != NULL ) && + ( H5C2_get_trace_file_ptr(f->shared->cache2, &trace_file_ptr) >= 0) && + ( trace_file_ptr != NULL ) ) { + + sprintf(trace, "H5AC2_mark_pinned_or_protected_entry_dirty 0x%lx", + (unsigned long)(((H5C2_cache_entry_t *)thing)->addr)); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + +#ifdef H5_HAVE_PARALLEL + + HDassert( cache_ptr ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( thing ); + + info_ptr = (H5AC2_info_t *)thing; + + if ( ( info_ptr->is_dirty == FALSE ) && + ( ! ( info_ptr->is_protected ) ) && + ( info_ptr->is_pinned ) && + ( NULL != cache_ptr->aux_ptr) ) { + + result = H5AC2_log_dirtied_entry(cache_ptr, + info_ptr, + info_ptr->addr, + FALSE, + 0); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, \ + "H5AC2_log_dirtied_entry() failed.") + } + } +#endif /* H5_HAVE_PARALLEL */ + + result = H5C2_mark_pinned_or_protected_entry_dirty(cache_ptr, thing); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, \ + "H5C2_mark_pinned_entry_dirty() failed.") + + } + +done: + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_mark_pinned_entry_dirty() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_rename + * + * Purpose: Use this function to notify the cache that an object's + * file address changed. + * + * If H5AC2_DEBUG is defined then this function checks + * that the old and new addresses don't correspond to the + * address of a protected object. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Jul 9 1997 + * + * Modifications: + * Robb Matzke, 1999-07-27 + * The OLD_ADDR and NEW_ADDR arguments are passed by value. + * + * JRM 5/17/04 + * Complete rewrite for the new meta-data cache. + * + * JRM - 6/7/04 + * Abstracted the guts of the function to H5C_rename_entry() + * in H5C.c, and then re-wrote the function as a wrapper for + * H5C_rename_entry(). + * + * JRM - 7/5/05 + * Added code to track dirty byte generation, and to trigger + * clean entry list propagation when it exceeds a user + * specified threshold. Note that this code only applies in + * the PHDF5 case. It should have no effect on either the + * serial or FPHSD5 cases. + * + * Note that this code presumes that the renamed entry will + * be present in all caches -- which it must be at present. + * To maintain this invarient, only rename entries immediately + * after you unprotect them. + * + * JRM - 6/6/06 + * Added trace file support. + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ +herr_t +H5AC2_rename(H5F_t *f, const H5AC2_class_t *type, haddr_t old_addr, haddr_t new_addr) +{ + herr_t result; + herr_t ret_value=SUCCEED; /* Return value */ +#ifdef H5_HAVE_PARALLEL + H5AC2_aux_t * aux_ptr = NULL; +#endif /* H5_HAVE_PARALLEL */ +#if H5AC2__TRACE_FILE_ENABLED + char trace[128] = ""; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_ENTER_NOAPI(H5AC2_rename, FAIL) + + HDassert(f); + HDassert(f->shared->cache2); + HDassert(type); + HDassert(H5F_addr_defined(old_addr)); + HDassert(H5F_addr_defined(new_addr)); + HDassert(H5F_addr_ne(old_addr, new_addr)); + +#if H5AC2__TRACE_FILE_ENABLED + /* For the rename call, only the old addr and new addr are really + * necessary in the trace file. Include the type id so we don't have to + * look it up. Also write the result to catch occult errors. + */ + if ( ( f != NULL ) && + ( f->shared != NULL ) && + ( f->shared->cache2 != NULL ) && + ( H5C2_get_trace_file_ptr(f->shared->cache2, &trace_file_ptr) >= 0) && + ( trace_file_ptr != NULL ) ) { + + sprintf(trace, "H5AC2_rename 0x%lx 0x%lx %d", + (unsigned long)old_addr, + (unsigned long)new_addr, + (int)(type->id)); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + +#ifdef H5_HAVE_PARALLEL + if ( NULL != (aux_ptr = f->shared->cache2->aux_ptr) ) { + + result = H5AC2_log_renamed_entry(f->shared->cache2, + old_addr, + new_addr); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "H5AC2_log_renamed_entry() failed.") + } + } +#endif /* H5_HAVE_PARALLEL */ + + result = H5C2_rename_entry(f->shared->cache2, + type, + old_addr, + new_addr); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTRENAME, FAIL, \ + "H5C2_rename_entry() failed.") + } + +#ifdef H5_HAVE_PARALLEL + if ( ( aux_ptr != NULL ) && + ( aux_ptr->dirty_bytes >= aux_ptr->dirty_bytes_threshold ) ) { + + result = H5AC2_propagate_flushed_and_still_clean_entries_list(f, + H5AC2_noblock_dxpl_id, + f->shared->cache2, + TRUE); + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "Can't propagate clean entries list.") + } + } +#endif /* H5_HAVE_PARALLEL */ + +done: + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_rename() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_pin_protected_entry() + * + * Purpose: Pin a protected cache entry. The entry must be protected + * at the time of call, and must be unpinned. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 4/27/06 + * + * Modifications: + * + * Added trace file support. 6/6/06 + * + * Modified code in support of revised cache API needed + * to permit journaling. JRM - 10/18/07 + * + *------------------------------------------------------------------------- + */ +herr_t +H5AC2_pin_protected_entry(H5F_t * f, + void * thing) +{ + H5C2_t *cache_ptr = f->shared->cache2; + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ +#if H5AC2__TRACE_FILE_ENABLED + char trace[128] = ""; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_ENTER_NOAPI(H5AC2_pin_protected_entry, FAIL) + +#if H5AC2__TRACE_FILE_ENABLED + /* For the pin protected entry call, only the addr is really necessary + * in the trace file. Also write the result to catch occult errors. + */ + if ( ( f != NULL ) && + ( f->shared != NULL ) && + ( f->shared->cache2 != NULL ) && + ( H5C2_get_trace_file_ptr(f->shared->cache2, &trace_file_ptr) >= 0) && + ( trace_file_ptr != NULL ) ) { + + sprintf(trace, "H5AC2_pin_protected_entry 0x%lx", + (unsigned long)(((H5C2_cache_entry_t *)thing)->addr)); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + result = H5C2_pin_protected_entry(cache_ptr, thing); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, \ + "H5C2_pin_protected_entry() failed.") + } + +done: + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_pin_protected_entry() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_protect + * + * Purpose: If the target entry is not in the cache, load it. If + * necessary, attempt to evict one or more entries to keep + * the cache within its maximum size. + * + * Mark the target entry as protected, and return its address + * to the caller. The caller must call H5AC2_unprotect() when + * finished with the entry. + * + * While it is protected, the entry may not be either evicted + * or flushed -- nor may it be accessed by another call to + * H5AC2_protect. Any attempt to do so will result in a failure. + * + * This comment is a re-write of the original Purpose: section. + * For historical interest, the original version is reproduced + * below: + * + * Original Purpose section: + * + * Similar to H5AC2_find() except the object is removed from + * the cache and given to the caller, preventing other parts + * of the program from modifying the protected object or + * preempting it from the cache. + * + * The caller must call H5AC2_unprotect() when finished with + * the pointer. + * + * If H5AC2_DEBUG is defined then we check that the + * requested object isn't already protected. + * + * Return: Success: Ptr to the object. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Sep 2 1997 + * + * Modifications: + * Robb Matzke, 1999-07-27 + * The ADDR argument is passed by value. + * + * Bill Wendling, 2003-09-10 + * Added parameter to indicate whether this is a READ or + * WRITE type of protect. + * + * JRM -- 5/17/04 + * Complete re-write for the new client cache. See revised + * Purpose section above. + * + * JRM - 6/7/04 + * Abstracted the guts of the function to H5C2_protect() + * in H5C2.c, and then re-wrote the function as a wrapper for + * H5C2_protect(). + * + * JRM - 6/6/06 + * Added trace file support. + * + * JRM - 3/18/07 + * Modified code to support the new flags parameter for + * H5C2_protect(). For now, that means passing in the + * H5C2_READ_ONLY_FLAG if rw == H5AC2_READ. + * + * Also updated the trace file output to save the + * rw parameter, since we are now doing something with it. + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ +void * +H5AC2_protect(H5F_t *f, + hid_t dxpl_id, + const H5AC2_class_t *type, + haddr_t addr, + size_t len, + const void *udata, + H5AC2_protect_t rw) +{ + /* char * fcn_name = "H5AC2_protect"; */ + unsigned protect_flags = H5C2__NO_FLAGS_SET; + void * thing = (void *)NULL; + void * ret_value; /* Return value */ +#if H5AC2__TRACE_FILE_ENABLED + char trace[128] = ""; + size_t trace_entry_size = 0; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_ENTER_NOAPI(H5AC2_protect, NULL) + + /* check args */ + HDassert(f); + HDassert(f->shared); + HDassert(f->shared->cache2); + HDassert(type); + HDassert(type->serialize); + HDassert(H5F_addr_defined(addr)); + + /* Check for invalid access request */ + if(0 == (f->intent & H5F_ACC_RDWR) && rw == H5AC2_WRITE) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "no write intent on file") + +#if H5AC2__TRACE_FILE_ENABLED + /* For the protect call, only the addr and type id is really necessary + * in the trace file. Include the size of the entry protected as a + * sanity check. Also indicate whether the call was successful to + * catch occult errors. + */ + if ( ( f != NULL ) && + ( f->shared != NULL ) && + ( f->shared->cache2 != NULL ) && + ( H5C2_get_trace_file_ptr(f->shared->cache2, &trace_file_ptr) >= 0) && + ( trace_file_ptr != NULL ) ) { + + char * rw_string; + + if ( rw == H5AC2_WRITE ) { + + rw_string = "H5AC2_WRITE"; + + } else if ( rw == H5AC2_READ ) { + + rw_string = "H5AC2_READ"; + + } else { + + rw_string = "???"; + } + + sprintf(trace, "H5AC2_protect 0x%lx %ld %d %s", + (unsigned long)addr, + (long)len, + (int)(type->id), + rw_string); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + if ( rw == H5AC2_READ ) { + + protect_flags |= H5C2__READ_ONLY_FLAG; + } + + thing = H5C2_protect(f->shared->cache2, + dxpl_id, + type, + addr, + len, + udata, + protect_flags); + + if ( thing == NULL ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "H5C2_protect() failed.") + } + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + /* make note of the entry size */ + trace_entry_size = ((H5C2_cache_entry_t *)thing)->size; + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + /* Set return value */ + ret_value = thing; + +done: + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + HDfprintf(trace_file_ptr, "%s %d %d\n", trace, + (int)trace_entry_size, + (int)(ret_value != NULL)); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_protect() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_resize_pinned_entry + * + * Purpose: Resize a pinned entry. The target entry MUST be + * be pinned, and MUST not be unprotected. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 7/5/06 + * + * Modifications: + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ +herr_t +H5AC2_resize_pinned_entry(H5F_t * f, + void * thing, + size_t new_size) +{ + H5C2_t *cache_ptr = f->shared->cache2; + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ +#if H5AC2__TRACE_FILE_ENABLED + char trace[128] = ""; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_ENTER_NOAPI(H5AC2_resize_pinned_entry, FAIL) + +#if H5AC2__TRACE_FILE_ENABLED + /* For the resize pinned entry call, only the addr, and new_size are + * really necessary in the trace file. Write the result to catch + * occult errors. + */ + if ( ( f != NULL ) && + ( f->shared != NULL ) && + ( f->shared->cache2 != NULL ) && + ( H5C2_get_trace_file_ptr(f->shared->cache2, &trace_file_ptr) >= 0) && + ( trace_file_ptr != NULL ) ) { + + sprintf(trace, "H5AC2_resize_pinned_entry 0x%lx %d", + (unsigned long)(((H5C2_cache_entry_t *)thing)->addr), + (int)new_size); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + +#ifdef H5_HAVE_PARALLEL + + HDassert( cache_ptr ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + HDassert( thing ); + + if ( ( ((H5AC2_info_t *)thing)->is_dirty == FALSE ) && + ( NULL != cache_ptr->aux_ptr) ) { + + H5AC2_info_t * entry_ptr; + + entry_ptr = (H5AC2_info_t *)thing; + + if ( ! ( entry_ptr->is_pinned ) ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTRESIZE, FAIL, \ + "Entry isn't pinned??") + } + + if ( entry_ptr->is_protected ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTRESIZE, FAIL, \ + "Entry is protected??") + } + + result = H5AC2_log_dirtied_entry(cache_ptr, + entry_ptr, + entry_ptr->addr, + TRUE, + new_size); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, \ + "H5AC2_log_dirtied_entry() failed.") + } + } +#endif /* H5_HAVE_PARALLEL */ + + result = H5C2_resize_pinned_entry(cache_ptr, + thing, + new_size); + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTRESIZE, FAIL, \ + "H5C2_resize_pinned_entry() failed.") + + } + +done: + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_resize_pinned_entry() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_unpin_entry() + * + * Purpose: Unpin a cache entry. The entry must be unprotected at + * the time of call, and must be pinned. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 4/11/06 + * + * Modifications: + * + * Added code supporting the trace file. JRM -- 6/7/06 + * + * Modified code in support of revised cache API needed + * to permit journaling. JRM - 10/18/07 + * + *------------------------------------------------------------------------- + */ +herr_t +H5AC2_unpin_entry(H5F_t * f, + void * thing) +{ + H5C2_t *cache_ptr = f->shared->cache2; + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ +#if H5AC2__TRACE_FILE_ENABLED + char trace[128] = ""; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_ENTER_NOAPI(H5AC2_unpin_entry, FAIL) + +#if H5AC2__TRACE_FILE_ENABLED + /* For the unpin entry call, only the addr is really necessary + * in the trace file. Also write the result to catch occult errors. + */ + if ( ( f != NULL ) && + ( f->shared != NULL ) && + ( f->shared->cache2 != NULL ) && + ( H5C2_get_trace_file_ptr(f->shared->cache2, &trace_file_ptr) >= 0) && + ( trace_file_ptr != NULL ) ) { + + sprintf(trace, "H5AC2_unpin_entry 0x%lx", + (unsigned long)(((H5C2_cache_entry_t *)thing)->addr)); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + result = H5C2_unpin_entry(cache_ptr, thing); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "H5C2_unpin_entry() failed.") + } + +done: + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + HDfprintf(trace_file_ptr, "%s %d\n", trace, (int)ret_value); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_unpin_entry() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_unprotect + * + * Purpose: Undo an H5AC2_protect() call -- specifically, mark the + * entry as unprotected, remove it from the protected list, + * and give it back to the replacement policy. + * + * The TYPE and ADDR arguments must be the same as those in + * the corresponding call to H5AC2_protect() and the THING + * argument must be the value returned by that call to + * H5AC2_protect(). + * + * If the deleted flag is TRUE, simply remove the target entry + * from the cache, clear it, and free it without writing it to + * disk. + * + * This verion of the function is a complete re-write to + * use the new metadata cache. While there isn't all that + * much difference between the old and new Purpose sections, + * the original version is given below. + * + * Original purpose section: + * + * This function should be called to undo the effect of + * H5AC2_protect(). The TYPE and ADDR arguments should be the + * same as the corresponding call to H5AC2_protect() and the + * THING argument should be the value returned by H5AC2_protect(). + * If the DELETED flag is set, then this object has been deleted + * from the file and should not be returned to the cache. + * + * If H5AC2_DEBUG is defined then this function fails + * if the TYPE and ADDR arguments are not what was used when the + * object was protected or if the object was never protected. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Sep 2 1997 + * + * Modifications: + * Robb Matzke, 1999-07-27 + * The ADDR argument is passed by value. + * + * Quincey Koziol, 2003-03-19 + * Added "deleted" argument + * + * Bill Wendling, 2003-09-18 + * If this is an FPHDF5 driver and the data is dirty, + * perform a "flush" that writes the data to the SAP. + * + * John Mainzer 5/19/04 + * Complete re-write for the new metadata cache. + * + * JRM - 6/7/04 + * Abstracted the guts of the function to H5C_unprotect() + * in H5C.c, and then re-wrote the function as a wrapper for + * H5C_unprotect(). + * + * JRM - 1/6/05 + * Replaced the deleted parameter with the new flags parameter. + * Since the deleted parameter is not used by the FPHDF5 code, + * the only change in the body is to replace the deleted + * parameter with the flags parameter in the call to + * H5C_unprotect(). + * + * JRM - 6/6/05 + * Added the dirtied flag and supporting code. This is + * part of a collection of changes directed at moving + * management of cache entry dirty flags into the H5C code. + * + * JRM - 7/5/05 + * Added code to track dirty byte generation, and to trigger + * clean entry list propagation when it exceeds a user + * specified threshold. Note that this code only applies in + * the PHDF5 case. It should have no effect on either the + * serial or FPHSD5 cases. + * + * JRM - 9/8/05 + * Added code to track entry size changes. This is necessary + * as it can effect dirty byte creation counts, thereby + * throwing the caches out of sync in the PHDF5 case. + * + * JRM - 5/16/06 + * Added code to use the new dirtied field in + * H5C_cache_entry_t in the test to see if the entry has + * been dirtied. + * + * JRM - 6/7/06 + * Added support for the trace file. + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + * Note that the H5AC2__SIZE_CHANGED_FLAG must now be set if + * the size of the entry has changed. + * + *------------------------------------------------------------------------- + */ +herr_t +H5AC2_unprotect(H5F_t *f, hid_t dxpl_id, const H5AC2_class_t *type, + haddr_t addr, size_t new_size, void *thing, unsigned flags) +{ + herr_t result; + herr_t ret_value=SUCCEED; /* Return value */ + hbool_t size_changed = FALSE; + hbool_t dirtied; +#ifdef H5_HAVE_PARALLEL + H5AC2_aux_t * aux_ptr = NULL; +#endif /* H5_HAVE_PARALLEL */ +#if H5AC2__TRACE_FILE_ENABLED + char trace[128] = ""; + unsigned trace_flags = 0; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_ENTER_NOAPI(H5AC2_unprotect, FAIL) + + HDassert(f); + HDassert(f->shared->cache2); + HDassert(type); + HDassert(type->deserialize); + HDassert(H5F_addr_defined(addr)); + HDassert(thing); + HDassert( ((H5AC2_info_t *)thing)->addr == addr ); + HDassert( ((H5AC2_info_t *)thing)->type == type ); + +#if H5AC2__TRACE_FILE_ENABLED + /* For the unprotect call, only the addr, type id, flags, and possible + * new size are really necessary in the trace file. Write the return + * value to catch occult errors. + */ + if ( ( f != NULL ) && + ( f->shared != NULL ) && + ( f->shared->cache2 != NULL ) && + ( H5C2_get_trace_file_ptr(f->shared->cache2, &trace_file_ptr) >= 0) && + ( trace_file_ptr != NULL ) ) { + + sprintf(trace, "H5AC2_unprotect 0x%lx %d", + (unsigned long)addr, + (int)(type->id)); + + trace_flags = flags; + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + dirtied = ( ( (flags & H5AC2__DIRTIED_FLAG) == H5AC2__DIRTIED_FLAG ) || + ( ((H5AC2_info_t *)thing)->dirtied ) ); + + size_changed = ( (flags & H5AC2__SIZE_CHANGED_FLAG) == + H5AC2__SIZE_CHANGED_FLAG ); + +#ifdef H5_HAVE_PARALLEL + if ( ( dirtied ) && ( ((H5AC2_info_t *)thing)->is_dirty == FALSE ) && + ( NULL != (aux_ptr = f->shared->cache2->aux_ptr) ) ) { + + result = H5AC2_log_dirtied_entry(f->shared->cache2, + (H5AC2_info_t *)thing, + addr, + size_changed, + new_size); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "H5AC2_log_dirtied_entry() failed.") + } + } + + if ( ( (flags & H5C2__DELETED_FLAG) != 0 ) && + ( NULL != (aux_ptr = f->shared->cache2->aux_ptr) ) && + ( aux_ptr->mpi_rank == 0 ) ) { + + result = H5AC2_log_deleted_entry(f->shared->cache2, + (H5AC2_info_t *)thing, + addr, + flags); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "H5AC2_log_deleted_entry() failed.") + } + } +#endif /* H5_HAVE_PARALLEL */ + + result = H5C2_unprotect(f->shared->cache2, + dxpl_id, + type, + addr, + thing, + flags, + new_size); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "H5C2_unprotect() failed.") + } + +#ifdef H5_HAVE_PARALLEL + if ( ( aux_ptr != NULL ) && + ( aux_ptr->dirty_bytes >= aux_ptr->dirty_bytes_threshold ) ) { + + result = H5AC2_propagate_flushed_and_still_clean_entries_list(f, + H5AC2_noblock_dxpl_id, + f->shared->cache2, + TRUE); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, \ + "Can't propagate clean entries list.") + } + } +#endif /* H5_HAVE_PARALLEL */ + +done: + +#if H5AC2__TRACE_FILE_ENABLED + if ( trace_file_ptr != NULL ) { + + HDfprintf(trace_file_ptr, "%s %d %x %d\n", + trace, + (int)new_size, + (unsigned)flags, + (int)ret_value); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_unprotect() */ + + +/*------------------------------------------------------------------------- + * Function: HA5C_set_write_done_callback + * + * Purpose: Set the value of the write_done callback. This callback + * is used to improve performance of the parallel test bed + * for the cache. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 5/11/06 + * + * Modifications: + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ + +#ifdef H5_HAVE_PARALLEL +herr_t +H5AC2_set_write_done_callback(H5C2_t * cache_ptr, + void (* write_done)(void)) +{ + herr_t ret_value = SUCCEED; /* Return value */ + H5AC2_aux_t * aux_ptr = NULL; + + FUNC_ENTER_NOAPI(H5AC2_set_write_done_callback, FAIL) + + /* This would normally be an assert, but we need to use an HGOTO_ERROR + * call to shut up the compiler. + */ + if ( ( ! cache_ptr ) || ( cache_ptr->magic != H5C2__H5C2_T_MAGIC ) ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr") + } + + aux_ptr = cache_ptr->aux_ptr; + + HDassert( aux_ptr != NULL ); + HDassert( aux_ptr->magic == H5AC2__H5AC2_AUX_T_MAGIC ); + + aux_ptr->write_done = write_done; + +done: + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_set_write_done_callback() */ +#endif /* H5_HAVE_PARALLEL */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_stats + * + * Purpose: Prints statistics about the cache. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke + * Thursday, October 30, 1997 + * + * Modifications: + * John Mainzer 5/19/04 + * Re-write to support the new metadata cache. + * + * JRM - 6/7/04 + * Abstracted the guts of the function to H5C_stats() + * in H5C.c, and then re-wrote the function as a wrapper for + * H5C_stats(). + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ +herr_t +H5AC2_stats(const H5F_t *f) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5AC2_stats, FAIL) + + HDassert(f); + HDassert(f->shared->cache2); + + /* at present, this can't fail */ + (void)H5C2_stats(f->shared->cache2, f->name, FALSE); + +done: + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_stats() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_get_cache_auto_resize_config + * + * Purpose: Wrapper function for H5C2_get_cache_auto_resize_config(). + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: John Mainzer + * 3/10/05 + * + * Modifications: + * + * JRM - 4/6/05 + * Reworked for the addition of struct H5AC2_cache_config_t. + * + * JRM - 10/25/05 + * Added support for the new dirty_bytes_threshold field of + * both H5AC2_cache_config_t and H5AC2_aux_t. + * + * JRM - 6/8/06 + * Added support for the new trace file related fields. + * + * JRM - 7/28/07 + * Added support for the new evictions enabled related fields. + * + * Observe that H5AC2_get_cache_auto_resize_config() and + * H5AC2_set_cache_auto_resize_config() are becoming generic + * metadata cache configuration routines as they gain + * switches for functions that are only tenuously related + * to auto resize configuration. + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ + +herr_t +H5AC2_get_cache_auto_resize_config(H5AC2_t * cache_ptr, + H5AC2_cache_config_t *config_ptr) +{ + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ + hbool_t evictions_enabled; + H5C2_auto_size_ctl_t internal_config; + + FUNC_ENTER_NOAPI(H5AC2_get_cache_auto_resize_config, FAIL) + + if ( ( cache_ptr == NULL ) + || +#ifdef H5_HAVE_PARALLEL + ( ( cache_ptr->aux_ptr != NULL ) + && + ( ((H5AC2_aux_t *)(cache_ptr->aux_ptr))->magic + != + H5AC2__H5AC2_AUX_T_MAGIC + ) + ) + || +#endif /* H5_HAVE_PARALLEL */ + ( config_ptr == NULL ) + || + ( config_ptr->version != H5AC2__CURR_CACHE_CONFIG_VERSION ) + ) + { + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Bad cache_ptr or config_ptr on entry.") + + } + + result = H5C2_get_cache_auto_resize_config((H5C2_t *)cache_ptr, + &internal_config); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_get_cache_auto_resize_config() failed.") + } + + result = H5C2_get_evictions_enabled((H5C2_t *)cache_ptr, + &evictions_enabled); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_get_resize_enabled() failed.") + } + + if ( internal_config.rpt_fcn == NULL ) { + + config_ptr->rpt_fcn_enabled = FALSE; + + } else { + + config_ptr->rpt_fcn_enabled = TRUE; + } + + config_ptr->open_trace_file = FALSE; + config_ptr->close_trace_file = FALSE; + config_ptr->trace_file_name[0] = '\0'; + config_ptr->evictions_enabled = evictions_enabled; + config_ptr->set_initial_size = internal_config.set_initial_size; + config_ptr->initial_size = internal_config.initial_size; + config_ptr->min_clean_fraction = internal_config.min_clean_fraction; + config_ptr->max_size = internal_config.max_size; + config_ptr->min_size = internal_config.min_size; + config_ptr->epoch_length = (long)(internal_config.epoch_length); + config_ptr->incr_mode = internal_config.incr_mode; + config_ptr->lower_hr_threshold = internal_config.lower_hr_threshold; + config_ptr->increment = internal_config.increment; + config_ptr->apply_max_increment = internal_config.apply_max_increment; + config_ptr->max_increment = internal_config.max_increment; + config_ptr->decr_mode = internal_config.decr_mode; + config_ptr->upper_hr_threshold = internal_config.upper_hr_threshold; + config_ptr->decrement = internal_config.decrement; + config_ptr->apply_max_decrement = internal_config.apply_max_decrement; + config_ptr->max_decrement = internal_config.max_decrement; + config_ptr->epochs_before_eviction = + (int)(internal_config.epochs_before_eviction); + config_ptr->apply_empty_reserve = internal_config.apply_empty_reserve; + config_ptr->empty_reserve = internal_config.empty_reserve; + +#ifdef H5_HAVE_PARALLEL + if ( cache_ptr->aux_ptr != NULL ) { + + config_ptr->dirty_bytes_threshold = + ((H5AC2_aux_t *)(cache_ptr->aux_ptr))->dirty_bytes_threshold; + + } else { +#endif /* H5_HAVE_PARALLEL */ + + config_ptr->dirty_bytes_threshold = H5AC2__DEFAULT_DIRTY_BYTES_THRESHOLD; + +#ifdef H5_HAVE_PARALLEL + } +#endif /* H5_HAVE_PARALLEL */ + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_get_cache_auto_resize_config() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_get_cache_size + * + * Purpose: Wrapper function for H5C2_get_cache_size(). + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: John Mainzer + * 3/11/05 + * + * Modifications: + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ + +herr_t +H5AC2_get_cache_size(H5AC2_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) +{ + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5AC2_get_cache_size, FAIL) + + result = H5C2_get_cache_size((H5C2_t *)cache_ptr, + max_size_ptr, + min_clean_size_ptr, + cur_size_ptr, + cur_num_entries_ptr); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_get_cache_size() failed.") + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_get_cache_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_get_cache_hit_rate + * + * Purpose: Wrapper function for H5C2_get_cache_hit_rate(). + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: John Mainzer + * 3/10/05 + * + * Modifications: + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ + +herr_t +H5AC2_get_cache_hit_rate(H5AC2_t * cache_ptr, + double * hit_rate_ptr) + +{ + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5AC2_get_cache_hit_rate, FAIL) + + result = H5C2_get_cache_hit_rate((H5C2_t *)cache_ptr, hit_rate_ptr); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_get_cache_hit_rate() failed.") + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_get_cache_hit_rate() */ + + +/*------------------------------------------------------------------------- + * + * Function: H5AC2_reset_cache_hit_rate_stats() + * + * Purpose: Wrapper function for H5C2_reset_cache_hit_rate_stats(). + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: John Mainzer, 3/10/05 + * + * Modifications: + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ + +herr_t +H5AC2_reset_cache_hit_rate_stats(H5AC2_t * cache_ptr) +{ + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5AC2_reset_cache_hit_rate_stats, FAIL) + + result = H5C2_reset_cache_hit_rate_stats((H5C2_t *)cache_ptr); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_reset_cache_hit_rate_stats() failed.") + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_reset_cache_hit_rate_stats() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_set_cache_auto_resize_config + * + * Purpose: Wrapper function for H5C2_set_cache_auto_resize_config(). + * + * Return: SUCCEED on success, and FAIL on failure. + * + * Programmer: John Mainzer + * 3/10/05 + * + * Modifications: + * + * John Mainzer -- 4/6/05 + * Updated for the addition of H5AC2_cache_config_t. + * + * John Mainzer -- 10/25/05 + * Added support for the new dirty_bytes_threshold field of + * both H5AC2_cache_config_t and H5AC2_aux_t. + * + * John Mainzer -- 6/7/06 + * Added trace file support. + * + * John Mainzer -- 7/28/07 + * Added support for the new evictions enabled related fields. + * + * Observe that H5AC2_get_cache_auto_resize_config() and + * H5AC2_set_cache_auto_resize_config() are becoming generic + * metadata cache configuration routines as they gain + * switches for functions that are only tenuously related + * to auto resize configuration. + * + * JRM - 10/18/07 + * Modified code in support of revised cache API needed + * to permit journaling. + * + *------------------------------------------------------------------------- + */ + +herr_t +H5AC2_set_cache_auto_resize_config(H5AC2_t * cache_ptr, + H5AC2_cache_config_t *config_ptr) +{ + /* const char * fcn_name = "H5AC2_set_cache_auto_resize_config"; */ + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ + H5C2_auto_size_ctl_t internal_config; +#if H5AC2__TRACE_FILE_ENABLED + H5AC2_cache_config_t trace_config = H5AC2__DEFAULT_CACHE_CONFIG; + FILE * trace_file_ptr = NULL; +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_ENTER_NOAPI(H5AC2_set_cache_auto_resize_config, FAIL) + +#if H5AC2__TRACE_FILE_ENABLED + /* Make note of the new configuration. Don't look up the trace file + * pointer, as that may change before we use it. + */ + if ( config_ptr != NULL ) { + + trace_config = *config_ptr; + + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + if ( ( cache_ptr == NULL ) +#ifdef H5_HAVE_PARALLEL + || + ( ( cache_ptr->aux_ptr != NULL ) + && + ( + ((H5AC2_aux_t *)(cache_ptr->aux_ptr))->magic + != + H5AC2__H5AC2_AUX_T_MAGIC + ) + ) +#endif /* H5_HAVE_PARALLEL */ + ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "bad cache_ptr on entry.") + } + + result = H5AC2_validate_config(config_ptr); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Bad cache configuration"); + } + + if ( config_ptr->open_trace_file ) { + + FILE * file_ptr = NULL; + + if ( H5C2_get_trace_file_ptr(cache_ptr, &file_ptr) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_get_trace_file_ptr() failed.") + } + + if ( ( ! ( config_ptr->close_trace_file ) ) && + ( file_ptr != NULL ) ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \ + "Trace file already open.") + } + } + + if ( + ( + config_ptr->dirty_bytes_threshold + < + H5AC2__MIN_DIRTY_BYTES_THRESHOLD + ) + || + ( + config_ptr->dirty_bytes_threshold + > + H5AC2__MAX_DIRTY_BYTES_THRESHOLD + ) + ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "config_ptr->dirty_bytes_threshold out of range.") + } + + if ( config_ptr->close_trace_file ) { + + if ( H5AC2_close_trace_file(cache_ptr) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5AC2_close_trace_file() failed.") + } + } + + if ( config_ptr->open_trace_file ) { + + if ( H5AC2_open_trace_file(cache_ptr, config_ptr->trace_file_name) < 0 ) + { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \ + "H5AC2_open_trace_file() failed.") + } + } + + if ( H5AC2_ext_config_2_int_config(config_ptr, &internal_config) != + SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5AC2_ext_config_2_int_config() failed.") + } + + result = H5C2_set_cache_auto_resize_config((H5C2_t *)cache_ptr, + &internal_config); + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_set_cache_auto_resize_config() failed.") + } + + + result = H5C2_set_evictions_enabled((H5C2_t *)cache_ptr, + config_ptr->evictions_enabled); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_set_evictions_enabled() failed.") + } + +#ifdef H5_HAVE_PARALLEL + if ( cache_ptr->aux_ptr != NULL ) { + + ((H5AC2_aux_t *)(cache_ptr->aux_ptr))->dirty_bytes_threshold = + config_ptr->dirty_bytes_threshold; + } +#endif /* H5_HAVE_PARALLEL */ + +done: + +#if H5AC2__TRACE_FILE_ENABLED + /* For the set cache auto resize config call, only the contents + * of the config is necessary in the trace file. Write the return + * value to catch occult errors. + */ + if ( ( cache_ptr != NULL ) && + ( H5C2_get_trace_file_ptr(cache_ptr, &trace_file_ptr) >= 0 ) && + ( trace_file_ptr != NULL ) ) { + + HDfprintf(trace_file_ptr, + "%s %d %d %d %d \"%s\" %d %d %d %f %d %d %ld %d %f %f %d %d %d %f %f %d %d %d %d %f %d %d\n", + "H5AC2_set_cache_auto_resize_config", + trace_config.version, + (int)(trace_config.rpt_fcn_enabled), + (int)(trace_config.open_trace_file), + (int)(trace_config.close_trace_file), + trace_config.trace_file_name, + (int)(trace_config.evictions_enabled), + (int)(trace_config.set_initial_size), + (int)(trace_config.initial_size), + trace_config.min_clean_fraction, + (int)(trace_config.max_size), + (int)(trace_config.min_size), + trace_config.epoch_length, + (int)(trace_config.incr_mode), + trace_config.lower_hr_threshold, + trace_config.increment, + (int)(trace_config.apply_max_increment), + (int)(trace_config.max_increment), + (int)(trace_config.decr_mode), + trace_config.upper_hr_threshold, + trace_config.decrement, + (int)(trace_config.apply_max_decrement), + (int)(trace_config.max_decrement), + trace_config.epochs_before_eviction, + (int)(trace_config.apply_empty_reserve), + trace_config.empty_reserve, + trace_config.dirty_bytes_threshold, + (int)ret_value); + } +#endif /* H5AC2__TRACE_FILE_ENABLED */ + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_set_cache_auto_resize_config() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_validate_config() + * + * Purpose: Run a sanity check on the contents of the supplied + * instance of H5AC2_cache_config_t. + * + * Do nothing and return SUCCEED if no errors are detected, + * and flag an error and return FAIL otherwise. + * + * At present, this function operates by packing the data + * from the instance of H5AC2_cache_config_t into an instance + * of H5C2_auto_size_ctl_t, and then calling + * H5C2_validate_resize_config(). As H5AC2_cache_config_t and + * H5C2_auto_size_ctl_t diverge, we may have to change this. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 4/6/05 + * + * Modifications: + * + * - Added code testing the trace file configuration fields. + * These tests are not comprehensive, as many errors cannot + * be caught until the directives contained in these fields + * are applied. + * JRM - 5/15/06 + * + * - Added code testing the evictions enabled field. At + * present this consists of verifying that if + * evictions_enabled is FALSE, then automatic cache + * resizing in disabled. + * + * JRM - 7/28/07 + * + * Modified code in support of revised cache API needed + * to permit journaling. + * JRM - 10/18/07 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5AC2_validate_config(H5AC2_cache_config_t * config_ptr) + +{ + herr_t result; + herr_t ret_value = SUCCEED; /* Return value */ + int name_len; + H5C2_auto_size_ctl_t internal_config; + + FUNC_ENTER_NOAPI(H5AC2_validate_config, FAIL) + + if ( config_ptr == NULL ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL config_ptr on entry.") + } + + if ( config_ptr->version != H5AC2__CURR_CACHE_CONFIG_VERSION ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Unknown config version.") + } + + if ( ( config_ptr->rpt_fcn_enabled != TRUE ) && + ( config_ptr->rpt_fcn_enabled != FALSE ) ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \ + "config_ptr->rpt_fcn_enabled must be either TRUE or FALSE.") + } + + if ( ( config_ptr->open_trace_file != TRUE ) && + ( config_ptr->open_trace_file != FALSE ) ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \ + "config_ptr->open_trace_file must be either TRUE or FALSE.") + } + + if ( ( config_ptr->close_trace_file != TRUE ) && + ( config_ptr->close_trace_file != FALSE ) ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \ + "config_ptr->close_trace_file must be either TRUE or FALSE.") + } + + /* don't bother to test trace_file_name unless open_trace_file is TRUE */ + if ( config_ptr->open_trace_file ) { + + /* Can't really test the trace_file_name field without trying to + * open the file, so we will content ourselves with a couple of + * sanity checks on the length of the file name. + */ + name_len = HDstrlen(config_ptr->trace_file_name); + + if ( name_len <= 0 ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \ + "config_ptr->trace_file_name is empty.") + + } else if ( name_len > H5AC2__MAX_TRACE_FILE_NAME_LEN ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \ + "config_ptr->trace_file_name too long.") + } + } + + if ( ( config_ptr->evictions_enabled != TRUE ) && + ( config_ptr->evictions_enabled != FALSE ) ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \ + "config_ptr->evictions_enabled must be either TRUE or FALSE.") + } + + if ( ( config_ptr->evictions_enabled == FALSE ) && + ( ( config_ptr->incr_mode != H5C2_incr__off ) || + ( config_ptr->incr_mode != H5C2_decr__off ) ) ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \ + "Can't disable evictions while auto-resize is enabled.") + } + + if ( config_ptr->dirty_bytes_threshold < H5AC2__MIN_DIRTY_BYTES_THRESHOLD ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "dirty_bytes_threshold too small.") + } else + if ( config_ptr->dirty_bytes_threshold > H5AC2__MAX_DIRTY_BYTES_THRESHOLD ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "dirty_bytes_threshold too big.") + } + + if ( H5AC2_ext_config_2_int_config(config_ptr, &internal_config) != + SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5AC2_ext_config_2_int_config() failed.") + } + + result = H5C2_validate_resize_config(&internal_config, + H5C2_RESIZE_CFG__VALIDATE_ALL); + + if ( result != SUCCEED ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error(s) in new config.") + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_validate_config() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_close_trace_file() + * + * Purpose: If a trace file is open, stop logging calls to the cache, + * and close the file. + * + * Note that the function does nothing if there is no trace + * file. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 6/2/06 + * + * Modifications: + * + * Modified code in support of revised cache API needed + * to permit journaling. + * JRM - 10/18/07 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5AC2_close_trace_file(H5AC2_t * cache_ptr) + +{ + herr_t ret_value = SUCCEED; /* Return value */ + FILE * trace_file_ptr = NULL; + + FUNC_ENTER_NOAPI(H5AC2_close_trace_file, FAIL) + + if ( cache_ptr == NULL ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL cache_ptr on entry.") + } + + if ( H5C2_get_trace_file_ptr(cache_ptr, &trace_file_ptr) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_get_trace_file_ptr() failed.") + } + + if ( trace_file_ptr != NULL ) { + + if ( H5C2_set_trace_file_ptr(cache_ptr, NULL) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_set_trace_file_ptr() failed.") + } + + if ( HDfclose(trace_file_ptr) != 0 ) { + + HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, \ + "can't close metadata cache trace file") + } + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_close_trace_file() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_open_trace_file() + * + * Purpose: Open a trace file, and start logging calls to the cache. + * + * This logging is done at the H5C2 level, and will only take + * place if H5C2_TRACE_FILE_ENABLED (defined in H5C2private.h) + * is TRUE. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 6/1/06 + * + * Modifications: + * + * Modified code in support of revised cache API needed + * to permit journaling. + * JRM - 10/18/07 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5AC2_open_trace_file(H5AC2_t * cache_ptr, + const char * trace_file_name) +{ + herr_t ret_value = SUCCEED; /* Return value */ + char file_name[H5AC2__MAX_TRACE_FILE_NAME_LEN + H5C2__PREFIX_LEN + 2]; + FILE * file_ptr = NULL; +#ifdef H5_HAVE_PARALLEL + H5AC2_aux_t * aux_ptr = NULL; +#endif /* H5_HAVE_PARALLEL */ + + FUNC_ENTER_NOAPI(H5AC2_open_trace_file, FAIL) + + HDassert(cache_ptr); + + if ( cache_ptr == NULL ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cache_ptr NULL on entry.") + } + + if ( trace_file_name == NULL ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, \ + "NULL trace_file_name on entry.") + } + + if ( HDstrlen(trace_file_name) > H5AC2__MAX_TRACE_FILE_NAME_LEN ) { + + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "trace file name too long.") + } + + if ( H5C2_get_trace_file_ptr(cache_ptr, &file_ptr) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_get_trace_file_ptr() failed.") + } + + if ( file_ptr != NULL ) { + + HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "trace file already open.") + } + +#ifdef H5_HAVE_PARALLEL + + aux_ptr = (H5AC2_aux_t *)(cache_ptr->aux_ptr); + + if ( cache_ptr->aux_ptr == NULL ) { + + sprintf(file_name, "%s", trace_file_name); + + } else { + + if ( aux_ptr->magic != H5AC2__H5AC2_AUX_T_MAGIC ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad aux_ptr->magic.") + } + + sprintf(file_name, "%s.%d", trace_file_name, aux_ptr->mpi_rank); + + } + + if ( HDstrlen(file_name) > + H5AC2__MAX_TRACE_FILE_NAME_LEN + H5C2__PREFIX_LEN + 1 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "cooked trace file name too long.") + } + +#else /* H5_HAVE_PARALLEL */ + + sprintf(file_name, "%s", trace_file_name); + +#endif /* H5_HAVE_PARALLEL */ + + if ( (file_ptr = HDfopen(file_name, "w")) == NULL ) { + + /* trace file open failed */ + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "trace file open failed.") + } + + HDfprintf(file_ptr, "### HDF5 metadata cache trace file version 1 ###\n"); + + if ( H5C2_set_trace_file_ptr(cache_ptr, file_ptr) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_set_trace_file_ptr() failed.") + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_open_trace_file() */ + + +/*************************************************************************/ +/**************************** Private Functions: *************************/ +/*************************************************************************/ + +/*------------------------------------------------------------------------- + * + * Function: H5AC2_broadcast_clean_list() + * + * Purpose: Broadcast the contents of the process 0 cleaned entry + * slist. In passing, also remove all entries from said + * list, and also remove any matching entries from the dirtied + * slist. + * + * This function must only be called by the process with + * MPI_rank 0. + * + * Return SUCCEED on success, and FAIL on failure. + * + * Return: Non-negative on success/Negative on failure. + * + * Programmer: John Mainzer, 7/1/05 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +#ifdef H5_HAVE_PARALLEL +static herr_t +H5AC2_broadcast_clean_list(H5AC2_t * cache_ptr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + haddr_t addr; + H5AC2_aux_t * aux_ptr = NULL; + H5SL_node_t * slist_node_ptr = NULL; + H5AC2_slist_entry_t * slist_entry_ptr = NULL; + MPI_Offset * buf_ptr = NULL; + size_t buf_size; + int i = 0; + int mpi_result; + int num_entries; + + FUNC_ENTER_NOAPI(H5AC2_broadcast_clean_list, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + + aux_ptr = (H5AC2_aux_t *)(cache_ptr->aux_ptr); + + HDassert( aux_ptr != NULL ); + HDassert( aux_ptr->magic == H5AC2__H5AC2_AUX_T_MAGIC ); + HDassert( aux_ptr->mpi_rank == 0 ); + HDassert( aux_ptr->c_slist_ptr != NULL ); + HDassert( H5SL_count(aux_ptr->c_slist_ptr) == + (size_t)(aux_ptr->c_slist_len) ); + + + /* First broadcast the number of entries in the list so that the + * receives can set up a buffer to receive them. If there aren't + * any, we are done. + */ + num_entries = aux_ptr->c_slist_len; + + mpi_result = MPI_Bcast(&num_entries, 1, MPI_INT, 0, aux_ptr->mpi_comm); + + if ( mpi_result != MPI_SUCCESS ) { + + HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed 1", mpi_result) + + } + + if ( num_entries > 0 ) + { + /* allocate a buffer to store the list of entry base addresses in */ + + buf_size = sizeof(MPI_Offset) * (size_t)num_entries; + + buf_ptr = (MPI_Offset *)H5MM_malloc(buf_size); + + if ( buf_ptr == NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "memory allocation failed for clean entry buffer") + } + + /* now load the entry base addresses into the buffer, emptying the + * cleaned entry list in passing + */ + + while ( NULL != (slist_node_ptr = H5SL_first(aux_ptr->c_slist_ptr) ) ) + { + slist_entry_ptr = H5SL_item(slist_node_ptr); + + HDassert(slist_entry_ptr->magic == H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC); + + HDassert( i < num_entries ); + + addr = slist_entry_ptr->addr; + + if ( H5FD_mpi_haddr_to_MPIOff(addr, &(buf_ptr[i])) < 0 ) { + + HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, \ + "can't convert from haddr to MPI off") + } + + i++; + + /* now remove the entry from the cleaned entry list */ + if ( H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&addr)) + != slist_entry_ptr ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \ + "Can't delete entry from cleaned entry slist.") + } + + slist_entry_ptr->magic = 0; + H5FL_FREE(H5AC2_slist_entry_t, slist_entry_ptr); + slist_entry_ptr = NULL; + + aux_ptr->c_slist_len -= 1; + + HDassert( aux_ptr->c_slist_len >= 0 ); + + /* and also remove the matching entry from the dirtied list + * if it exists. + */ + if ( (slist_entry_ptr = H5SL_search(aux_ptr->d_slist_ptr, + (void *)(&addr))) != NULL ) { + + HDassert( slist_entry_ptr->magic == + H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC ); + HDassert( slist_entry_ptr->addr == addr ); + + if ( H5SL_remove(aux_ptr->d_slist_ptr, (void *)(&addr)) + != slist_entry_ptr ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \ + "Can't delete entry from dirty entry slist.") + } + + slist_entry_ptr->magic = 0; + H5FL_FREE(H5AC2_slist_entry_t, slist_entry_ptr); + slist_entry_ptr = NULL; + + aux_ptr->d_slist_len -= 1; + + HDassert( aux_ptr->d_slist_len >= 0 ); + } + + } /* while */ + + + /* Now broadcast the list of cleaned entries -- if there is one. + * + * The peculiar structure of the following call to MPI_Bcast is + * due to MPI's (?) failure to believe in the MPI_Offset type. + * Thus the element type is MPI_BYTE, with size equal to the + * buf_size computed above. + */ + + mpi_result = MPI_Bcast((void *)buf_ptr, (int)buf_size, MPI_BYTE, 0, + aux_ptr->mpi_comm); + + if ( mpi_result != MPI_SUCCESS ) { + + HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed 2", mpi_result) + } + } + +done: + + if ( buf_ptr != NULL ) { + + buf_ptr = (MPI_Offset *)H5MM_xfree((void *)buf_ptr); + } + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_broadcast_clean_list() */ +#endif /* H5_HAVE_PARALLEL */ + + +/*------------------------------------------------------------------------- + * + * Function: H5AC2_check_if_write_permitted + * + * Purpose: Determine if a write is permitted under the current + * circumstances, and set *write_permitted_ptr accordingly. + * As a general rule it is, but when we are running in parallel + * mode with collective I/O, we must ensure that a read cannot + * cause a write. + * + * In the event of failure, the value of *write_permitted_ptr + * is undefined. + * + * Return: Non-negative on success/Negative on failure. + * + * Programmer: John Mainzer, 5/15/04 + * + * Modifications: + * + * John Mainzer, 9/23/05 + * Rewrote function to return the value of the + * write_permitted field in aux structure if the structure + * exists and mpi_rank is 0. + * + * If the aux structure exists, but mpi_rank isn't 0, the + * function now returns FALSE. + * + * In all other cases, the function returns TRUE. + * + *------------------------------------------------------------------------- + */ + +#ifdef H5_HAVE_PARALLEL +static herr_t +H5AC2_check_if_write_permitted(const H5F_t *f, + hid_t UNUSED dxpl_id, + hbool_t * write_permitted_ptr) +#else /* H5_HAVE_PARALLEL */ +static herr_t +H5AC2_check_if_write_permitted(const H5F_t UNUSED * f, + hid_t UNUSED dxpl_id, + hbool_t * write_permitted_ptr) +#endif /* H5_HAVE_PARALLEL */ +{ + hbool_t write_permitted = TRUE; + herr_t ret_value = SUCCEED; /* Return value */ +#ifdef H5_HAVE_PARALLEL + H5AC2_aux_t * aux_ptr = NULL; +#endif /* H5_HAVE_PARALLEL */ + + + FUNC_ENTER_NOAPI(H5AC2_check_if_write_permitted, FAIL) + +#ifdef H5_HAVE_PARALLEL + HDassert( f != NULL ); + HDassert( f->shared != NULL ); + HDassert( f->shared->cache2 != NULL ); + + aux_ptr = (H5AC2_aux_t *)(f->shared->cache2->aux_ptr); + + if ( aux_ptr != NULL ) { + + HDassert( aux_ptr->magic == H5AC2__H5AC2_AUX_T_MAGIC ); + + if ( aux_ptr->mpi_rank == 0 ) { + + write_permitted = aux_ptr->write_permitted; + + } else { + + write_permitted = FALSE; + } + } +#endif /* H5_HAVE_PARALLEL */ + + *write_permitted_ptr = write_permitted; + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_check_if_write_permitted() */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_ext_config_2_int_config() + * + * Purpose: Utility function to translate an instance of + * H5AC2_cache_config_t to an instance of H5C2_auto_size_ctl_t. + * + * Places translation in *int_conf_ptr and returns SUCCEED + * if successful. Returns FAIL on failure. + * + * Does only minimal sanity checking. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: John Mainzer + * 1/26/06 + * + * Modifications: + * + * None. + * + *------------------------------------------------------------------------- + */ + +herr_t +H5AC2_ext_config_2_int_config(H5AC2_cache_config_t * ext_conf_ptr, + H5C2_auto_size_ctl_t * int_conf_ptr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5AC2_ext_config_2_int_config, FAIL) + + if ( ( ext_conf_ptr == NULL ) || + ( ext_conf_ptr->version != H5AC2__CURR_CACHE_CONFIG_VERSION ) || + ( int_conf_ptr == NULL ) ) { + + } + + int_conf_ptr->version = H5C2__CURR_AUTO_SIZE_CTL_VER; + + if ( ext_conf_ptr->rpt_fcn_enabled ) { + + int_conf_ptr->rpt_fcn = H5C2_def_auto_resize_rpt_fcn; + + } else { + + int_conf_ptr->rpt_fcn = NULL; + } + + int_conf_ptr->set_initial_size = ext_conf_ptr->set_initial_size; + int_conf_ptr->initial_size = ext_conf_ptr->initial_size; + int_conf_ptr->min_clean_fraction = ext_conf_ptr->min_clean_fraction; + int_conf_ptr->max_size = ext_conf_ptr->max_size; + int_conf_ptr->min_size = ext_conf_ptr->min_size; + int_conf_ptr->epoch_length = + (int64_t)(ext_conf_ptr->epoch_length); + + int_conf_ptr->incr_mode = ext_conf_ptr->incr_mode; + int_conf_ptr->lower_hr_threshold = ext_conf_ptr->lower_hr_threshold; + int_conf_ptr->increment = ext_conf_ptr->increment; + int_conf_ptr->apply_max_increment = ext_conf_ptr->apply_max_increment; + int_conf_ptr->max_increment = ext_conf_ptr->max_increment; + + int_conf_ptr->decr_mode = ext_conf_ptr->decr_mode; + int_conf_ptr->upper_hr_threshold = ext_conf_ptr->upper_hr_threshold; + int_conf_ptr->decrement = ext_conf_ptr->decrement; + int_conf_ptr->apply_max_decrement = ext_conf_ptr->apply_max_decrement; + int_conf_ptr->max_decrement = ext_conf_ptr->max_decrement; + int_conf_ptr->epochs_before_eviction = + (int32_t)(ext_conf_ptr->epochs_before_eviction); + int_conf_ptr->apply_empty_reserve = ext_conf_ptr->apply_empty_reserve; + int_conf_ptr->empty_reserve = ext_conf_ptr->empty_reserve; + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_ext_config_2_int_config() */ + + +/*------------------------------------------------------------------------- + * + * Function: H5AC2_log_deleted_entry() + * + * Purpose: Log an entry for which H5C2__DELETED_FLAG has been set. + * + * If mpi_rank is 0, we must make sure that the entry doesn't + * appear in the cleaned or dirty entry lists. Otherwise, + * we have nothing to do. + * + * Return SUCCEED on success, and FAIL on failure. + * + * Return: Non-negative on success/Negative on failure. + * + * Programmer: John Mainzer, 6/29/05 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +#ifdef H5_HAVE_PARALLEL +static herr_t +H5AC2_log_deleted_entry(H5AC2_t * cache_ptr, + H5AC2_info_t * entry_ptr, + haddr_t addr, + unsigned int flags) +{ + herr_t ret_value = SUCCEED; /* Return value */ + H5AC2_aux_t * aux_ptr = NULL; + H5AC2_slist_entry_t * slist_entry_ptr = NULL; + + FUNC_ENTER_NOAPI(H5AC2_log_deleted_entry, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + + aux_ptr = cache_ptr->aux_ptr; + + HDassert( aux_ptr != NULL ); + HDassert( aux_ptr->magic == H5AC2__H5AC2_AUX_T_MAGIC ); + + HDassert( entry_ptr != NULL ); + HDassert( entry_ptr->addr == addr ); + + HDassert( (flags & H5C2__DELETED_FLAG) != 0 ); + + if ( aux_ptr->mpi_rank == 0 ) { + + HDassert( aux_ptr->d_slist_ptr != NULL ); + HDassert( aux_ptr->c_slist_ptr != NULL ); + + /* if the entry appears in the dirtied entry slist, remove it. */ + if ( (slist_entry_ptr = H5SL_search(aux_ptr->d_slist_ptr, + (void *)(&addr))) != NULL ) { + + HDassert( slist_entry_ptr->magic == + H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC ); + HDassert( slist_entry_ptr->addr == addr ); + + if ( H5SL_remove(aux_ptr->d_slist_ptr, (void *)(&addr)) + != slist_entry_ptr ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \ + "Can't delete entry from dirty entry slist.") + } + + slist_entry_ptr->magic = 0; + H5FL_FREE(H5AC2_slist_entry_t, slist_entry_ptr); + slist_entry_ptr = NULL; + + aux_ptr->d_slist_len -= 1; + + HDassert( aux_ptr->d_slist_len >= 0 ); + } + + /* if the entry appears in the cleaned entry slist, remove it. */ + if ( (slist_entry_ptr = H5SL_search(aux_ptr->c_slist_ptr, + (void *)(&addr))) != NULL ) { + + HDassert( slist_entry_ptr->magic == + H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC ); + HDassert( slist_entry_ptr->addr == addr ); + + if ( H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&addr)) + != slist_entry_ptr ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \ + "Can't delete entry from cleaned entry slist.") + } + + slist_entry_ptr->magic = 0; + H5FL_FREE(H5AC2_slist_entry_t, slist_entry_ptr); + slist_entry_ptr = NULL; + + aux_ptr->c_slist_len -= 1; + + HDassert( aux_ptr->c_slist_len >= 0 ); + } + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_log_deleted_entry() */ +#endif /* H5_HAVE_PARALLEL */ + + +/*------------------------------------------------------------------------- + * + * Function: H5AC2_log_dirtied_entry() + * + * Purpose: Update the dirty_bytes count for a newly dirtied entry. + * + * If mpi_rank isnt 0, this simply means adding the size + * of the entries to the dirty_bytes count. + * + * If mpi_rank is 0, we must first check to see if the entry + * appears in the dirty entries slist. If it is, do nothing. + * If it isn't, add the size to th dirty_bytes count, add the + * entry to the dirty entries slist, and remove it from the + * cleaned list (if it is present there). + * + * Return SUCCEED on success, and FAIL on failure. + * + * Return: Non-negative on success/Negative on failure. + * + * Programmer: John Mainzer, 6/29/05 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +#ifdef H5_HAVE_PARALLEL +static herr_t +H5AC2_log_dirtied_entry(H5AC2_t * cache_ptr, + H5AC2_info_t * entry_ptr, + haddr_t addr, + hbool_t size_changed, + size_t new_size) +{ + herr_t ret_value = SUCCEED; /* Return value */ + size_t entry_size; + H5AC2_aux_t * aux_ptr = NULL; + H5AC2_slist_entry_t * slist_entry_ptr = NULL; + + FUNC_ENTER_NOAPI(H5AC2_log_dirtied_entry, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + + aux_ptr = cache_ptr->aux_ptr; + + HDassert( aux_ptr != NULL ); + HDassert( aux_ptr->magic == H5AC2__H5AC2_AUX_T_MAGIC ); + + HDassert( entry_ptr != NULL ); + HDassert( entry_ptr->addr == addr ); + HDassert( entry_ptr->is_dirty == FALSE ); + + if ( size_changed ) { + + entry_size = new_size; + + } else { + + entry_size = entry_ptr->size; + } + + if ( aux_ptr->mpi_rank == 0 ) { + + HDassert( aux_ptr->d_slist_ptr != NULL ); + HDassert( aux_ptr->c_slist_ptr != NULL ); + + if ( H5SL_search(aux_ptr->d_slist_ptr, (void *)(&addr)) == NULL ) { + + /* insert the address of the entry in the dirty entry list, and + * add its size to the dirty_bytes count. + */ + if ( NULL == (slist_entry_ptr = H5FL_CALLOC(H5AC2_slist_entry_t)) ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "Can't allocate dirty slist entry .") + } + + slist_entry_ptr->magic = H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC; + slist_entry_ptr->addr = addr; + + if ( H5SL_insert(aux_ptr->d_slist_ptr, slist_entry_ptr, + &(slist_entry_ptr->addr)) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, \ + "can't insert entry into dirty entry slist.") + } + + aux_ptr->d_slist_len += 1; + aux_ptr->dirty_bytes += entry_size; +#if H5AC2_DEBUG_DIRTY_BYTES_CREATION + aux_ptr->unprotect_dirty_bytes += entry_size; + aux_ptr->unprotect_dirty_bytes_updates += 1; +#endif /* H5AC2_DEBUG_DIRTY_BYTES_CREATION */ + } + + if ( H5SL_search(aux_ptr->c_slist_ptr, (void *)(&addr)) != NULL ) { + + /* the entry is dirty. If it exists on the cleaned entries list, + * remove it. + */ + if ( (slist_entry_ptr = H5SL_search(aux_ptr->c_slist_ptr, + (void *)(&addr))) != NULL ) { + + HDassert( slist_entry_ptr->magic == + H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC ); + HDassert( slist_entry_ptr->addr == addr ); + + if ( H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&addr)) + != slist_entry_ptr ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \ + "Can't delete entry from clean entry slist.") + } + + slist_entry_ptr->magic = 0; + H5FL_FREE(H5AC2_slist_entry_t, slist_entry_ptr); + slist_entry_ptr = NULL; + + aux_ptr->c_slist_len -= 1; + + HDassert( aux_ptr->c_slist_len >= 0 ); + } + } + } else { + + aux_ptr->dirty_bytes += entry_size; +#if H5AC2_DEBUG_DIRTY_BYTES_CREATION + aux_ptr->unprotect_dirty_bytes += entry_size; + aux_ptr->unprotect_dirty_bytes_updates += 1; +#endif /* H5AC2_DEBUG_DIRTY_BYTES_CREATION */ + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_log_dirtied_entry() */ +#endif /* H5_HAVE_PARALLEL */ + + +/*------------------------------------------------------------------------- + * + * Function: H5AC2_log_flushed_entry() + * + * Purpose: Update the clean entry slist for the flush of an entry -- + * specifically, if the entry has been cleared, remove it + * from both the cleaned and dirtied lists if it is present. + * Otherwise, if the entry was dirty, insert the indicated + * entry address in the clean slist if it isn't there already. + * + * This function is only used in PHDF5, and should only + * be called for the process with mpi rank 0. + * + * Return SUCCEED on success, and FAIL on failure. + * + * Return: Non-negative on success/Negative on failure. + * + * Programmer: John Mainzer, 6/29/05 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +#ifdef H5_HAVE_PARALLEL +#if 0 /* This is useful debugging code. -- JRM */ +static herr_t +H5AC2_log_flushed_entry_dummy(H5C2_t * cache_ptr, + haddr_t addr, + hbool_t was_dirty, + unsigned flags, + int type_id) +{ + herr_t ret_value = SUCCEED; /* Return value */ + H5AC2_aux_t * aux_ptr = NULL; + + FUNC_ENTER_NOAPI(H5AC2_log_flushed_entry_dummy, FAIL) + + aux_ptr = cache_ptr->aux_ptr; + + if ( ( was_dirty ) && ( (flags & H5C2__FLUSH_CLEAR_ONLY_FLAG) == 0 ) ) { + + HDfprintf(stdout, + "%d:H5AC2_log_flushed_entry(): addr = %d, flags = %x, was_dirty = %d, type_id = %d\n", + (int)(aux_ptr->mpi_rank), (int)addr, flags, (int)was_dirty, type_id); + } +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_log_flushed_entry_dummy() */ +#endif /* JRM */ + +static herr_t +H5AC2_log_flushed_entry(H5C2_t * cache_ptr, + haddr_t addr, + hbool_t was_dirty, + unsigned flags, + int UNUSED type_id) +{ + herr_t ret_value = SUCCEED; /* Return value */ + hbool_t cleared; + H5AC2_aux_t * aux_ptr; + H5AC2_slist_entry_t * slist_entry_ptr = NULL; + + + FUNC_ENTER_NOAPI(H5AC2_log_flushed_entry, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + + aux_ptr = cache_ptr->aux_ptr; + + HDassert( aux_ptr != NULL ); + HDassert( aux_ptr->magic == H5AC2__H5AC2_AUX_T_MAGIC ); + HDassert( aux_ptr->mpi_rank == 0 ); + HDassert( aux_ptr->c_slist_ptr != NULL ); + + cleared = ( (flags & H5C2__FLUSH_CLEAR_ONLY_FLAG) != 0 ); + + if ( cleared ) { + + /* If the entry has been cleared, must remove it from both the + * cleaned list and the dirtied list. + */ + + if ( (slist_entry_ptr = H5SL_search(aux_ptr->c_slist_ptr, + (void *)(&addr))) != NULL ) { + + HDassert( slist_entry_ptr->magic == H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC); + HDassert( slist_entry_ptr->addr == addr ); + + if ( H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&addr)) + != slist_entry_ptr ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \ + "Can't delete entry from clean entry slist.") + } + + slist_entry_ptr->magic = 0; + H5FL_FREE(H5AC2_slist_entry_t, slist_entry_ptr); + slist_entry_ptr = NULL; + + aux_ptr->c_slist_len -= 1; + + HDassert( aux_ptr->c_slist_len >= 0 ); + } + + if ( (slist_entry_ptr = H5SL_search(aux_ptr->d_slist_ptr, + (void *)(&addr))) != NULL ) { + + HDassert( slist_entry_ptr->magic == H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC); + HDassert( slist_entry_ptr->addr == addr ); + + if ( H5SL_remove(aux_ptr->d_slist_ptr, (void *)(&addr)) + != slist_entry_ptr ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \ + "Can't delete entry from dirty entry slist.") + } + + slist_entry_ptr->magic = 0; + H5FL_FREE(H5AC2_slist_entry_t, slist_entry_ptr); + slist_entry_ptr = NULL; + + aux_ptr->d_slist_len -= 1; + + HDassert( aux_ptr->d_slist_len >= 0 ); + } + } else if ( was_dirty ) { + + if ( H5SL_search(aux_ptr->c_slist_ptr, (void *)(&addr)) == NULL ) { + + /* insert the address of the entry in the clean entry list. */ + + if ( NULL == (slist_entry_ptr = H5FL_CALLOC(H5AC2_slist_entry_t)) ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "Can't allocate clean slist entry .") + } + + slist_entry_ptr->magic = H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC; + slist_entry_ptr->addr = addr; + + if ( H5SL_insert(aux_ptr->c_slist_ptr, slist_entry_ptr, + &(slist_entry_ptr->addr)) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, \ + "can't insert entry into clean entry slist.") + } + + aux_ptr->c_slist_len += 1; + } + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_log_flushed_entry() */ +#endif /* H5_HAVE_PARALLEL */ + + +/*------------------------------------------------------------------------- + * + * Function: H5AC2_log_inserted_entry() + * + * Purpose: Update the dirty_bytes count for a newly inserted entry. + * + * If mpi_rank isnt 0, this simply means adding the size + * of the entry to the dirty_bytes count. + * + * If mpi_rank is 0, we must also add the entry to the + * dirty entries slist. + * + * Return SUCCEED on success, and FAIL on failure. + * + * Return: Non-negative on success/Negative on failure. + * + * Programmer: John Mainzer, 6/30/05 + * + * Modifications: + * + * JRM -- 10/24/07 + * Added the size parameter. + * + *------------------------------------------------------------------------- + */ + +#ifdef H5_HAVE_PARALLEL +static herr_t +H5AC2_log_inserted_entry(H5F_t * f, + H5AC2_t * cache_ptr, + H5AC2_info_t * entry_ptr, + const H5AC2_class_t * type, + haddr_t addr, + size_t size) +{ + herr_t ret_value = SUCCEED; /* Return value */ + H5AC2_aux_t * aux_ptr = NULL; + H5AC2_slist_entry_t * slist_entry_ptr = NULL; + + FUNC_ENTER_NOAPI(H5AC2_log_inserted_entry, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + + aux_ptr = cache_ptr->aux_ptr; + + HDassert( aux_ptr != NULL ); + HDassert( aux_ptr->magic == H5AC2__H5AC2_AUX_T_MAGIC ); + + HDassert( entry_ptr != NULL ); + HDassert( entry_ptr->addr == addr ); + HDassert( entry_ptr->type == type ); + + if ( aux_ptr->mpi_rank == 0 ) { + + HDassert( aux_ptr->d_slist_ptr != NULL ); + HDassert( aux_ptr->c_slist_ptr != NULL ); + + if ( H5SL_search(aux_ptr->d_slist_ptr, (void *)(&addr)) == NULL ) { + + /* insert the address of the entry in the dirty entry list, and + * add its size to the dirty_bytes count. + */ + if ( NULL == (slist_entry_ptr = H5FL_CALLOC(H5AC2_slist_entry_t)) ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "Can't allocate dirty slist entry .") + } + + slist_entry_ptr->magic = H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC; + slist_entry_ptr->addr = addr; + + if ( H5SL_insert(aux_ptr->d_slist_ptr, slist_entry_ptr, + &(slist_entry_ptr->addr)) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, \ + "can't insert entry into dirty entry slist.") + } + + aux_ptr->d_slist_len += 1; + + } else { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Inserted entry already in dirty slist.") + } + + if ( H5SL_search(aux_ptr->c_slist_ptr, (void *)(&addr)) != NULL ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Inserted entry in clean slist.") + } + } + + aux_ptr->dirty_bytes += size; + +#if H5AC2_DEBUG_DIRTY_BYTES_CREATION + aux_ptr->insert_dirty_bytes += size; + aux_ptr->insert_dirty_bytes_updates += 1; +#endif /* H5AC2_DEBUG_DIRTY_BYTES_CREATION */ + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_log_inserted_entry() */ +#endif /* H5_HAVE_PARALLEL */ + + +/*------------------------------------------------------------------------- + * + * Function: H5AC2_log_renamed_entry() + * + * Purpose: Update the dirty_bytes count for a renamed entry. + * + * WARNING + * + * At present, the way that the rename call is used ensures + * that the renamed entry is present in all caches by + * renaming in a collective operation and immediately after + * unprotecting the target entry. + * + * This function uses this invarient, and will cause arcane + * failures if it is not met. If maintaining this invarient + * becomes impossible, we will have to rework this function + * extensively, and likely include a bit of IPC for + * synchronization. A better option might be to subsume + * rename in the unprotect operation. + * + * Given that the target entry is in all caches, the function + * proceeds as follows: + * + * For processes with mpi rank other 0, it simply checks to + * see if the entry was dirty prior to the rename, and adds + * the entries size to the dirty bytes count. + * + * In the process with mpi rank 0, the function first checks + * to see if the entry was dirty prior to the rename. If it + * was, and if the entry doesn't appear in the dirtied list + * under its old address, it adds the entry's size to the + * dirty bytes count. + * + * The rank 0 process then removes any references to the + * entry under its old address from the cleands and dirtied + * lists, and inserts an entry in the dirtied list under the + * new address. + * + * Return SUCCEED on success, and FAIL on failure. + * + * Return: Non-negative on success/Negative on failure. + * + * Programmer: John Mainzer, 6/30/05 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +#ifdef H5_HAVE_PARALLEL +static herr_t +H5AC2_log_renamed_entry(H5AC2_t * cache_ptr, + haddr_t old_addr, + haddr_t new_addr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + hbool_t entry_in_cache; + hbool_t entry_dirty; + size_t entry_size; + H5AC2_aux_t * aux_ptr = NULL; + H5AC2_slist_entry_t * slist_entry_ptr = NULL; + + FUNC_ENTER_NOAPI(H5AC2_log_renamed_entry, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + + aux_ptr = cache_ptr->aux_ptr; + + HDassert( aux_ptr != NULL ); + HDassert( aux_ptr->magic == H5AC2__H5AC2_AUX_T_MAGIC ); + + /* get entry status, size, etc here */ + if ( H5C2_get_entry_status(cache_ptr, old_addr, &entry_size, &entry_in_cache, + &entry_dirty, NULL, NULL) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't get entry status.") + + } else if ( ! entry_in_cache ) { + + HDassert( entry_in_cache ); + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "entry not in cache.") + } + + if ( aux_ptr->mpi_rank == 0 ) { + + HDassert( aux_ptr->d_slist_ptr != NULL ); + HDassert( aux_ptr->c_slist_ptr != NULL ); + + /* if the entry appears in the cleaned entry slist, under its old + * address, remove it. + */ + if ( (slist_entry_ptr = H5SL_search(aux_ptr->c_slist_ptr, + (void *)(&old_addr))) != NULL ) { + + HDassert( slist_entry_ptr->magic == + H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC ); + HDassert( slist_entry_ptr->addr == old_addr ); + + if ( H5SL_remove(aux_ptr->c_slist_ptr, (void *)(&old_addr)) + != slist_entry_ptr ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \ + "Can't delete entry from cleaned entry slist.") + } + + slist_entry_ptr->magic = 0; + H5FL_FREE(H5AC2_slist_entry_t, slist_entry_ptr); + slist_entry_ptr = NULL; + + aux_ptr->c_slist_len -= 1; + + HDassert( aux_ptr->c_slist_len >= 0 ); + } + + /* if the entry appears in the dirtied entry slist under its old + * address, remove it, but don't free it. Set addr to new_addr. + */ + if ( (slist_entry_ptr = H5SL_search(aux_ptr->d_slist_ptr, + (void *)(&old_addr))) != NULL ) { + + HDassert( slist_entry_ptr->magic == + H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC ); + HDassert( slist_entry_ptr->addr == old_addr ); + + if ( H5SL_remove(aux_ptr->d_slist_ptr, (void *)(&old_addr)) + != slist_entry_ptr ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTDELETE, FAIL, \ + "Can't delete entry from dirty entry slist.") + } + + slist_entry_ptr->addr = new_addr; + + aux_ptr->d_slist_len -= 1; + + HDassert( aux_ptr->d_slist_len >= 0 ); + + } else { + + /* otherwise, allocate a new entry that is ready + * for insertion, and increment dirty_bytes. + * + * Note that the fact that the entry wasn't in the dirtied + * list under its old address implies that it must have + * been clean to start with. + */ + + HDassert( !entry_dirty ); + + if ( NULL == (slist_entry_ptr = H5FL_CALLOC(H5AC2_slist_entry_t)) ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "Can't allocate dirty slist entry .") + } + + slist_entry_ptr->magic = H5AC2__H5AC2_SLIST_ENTRY_T_MAGIC; + slist_entry_ptr->addr = new_addr; + + aux_ptr->dirty_bytes += entry_size; + +#if H5AC2_DEBUG_DIRTY_BYTES_CREATION + aux_ptr->rename_dirty_bytes += entry_size; + aux_ptr->rename_dirty_bytes_updates += 1; +#endif /* H5AC2_DEBUG_DIRTY_BYTES_CREATION */ + } + + /* verify that there is no entry at new_addr in the dirty slist */ + if ( H5SL_search(aux_ptr->d_slist_ptr, (void *)(&new_addr)) != NULL ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "dirty slist already contains entry at new_addr.") + } + + /* insert / reinsert the entry in the dirty slist */ + if ( H5SL_insert(aux_ptr->d_slist_ptr, slist_entry_ptr, + &(slist_entry_ptr->addr)) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTINSERT, FAIL, \ + "can't insert entry into dirty entry slist.") + } + + aux_ptr->d_slist_len += 1; + + } else if ( ! entry_dirty ) { + + aux_ptr->dirty_bytes += entry_size; + +#if H5AC2_DEBUG_DIRTY_BYTES_CREATION + aux_ptr->rename_dirty_bytes += entry_size; + aux_ptr->rename_dirty_bytes_updates += 1; +#endif /* H5AC2_DEBUG_DIRTY_BYTES_CREATION */ + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_log_renamed_entry() */ +#endif /* H5_HAVE_PARALLEL */ + + +/*------------------------------------------------------------------------- + * Function: H5AC2_propagate_flushed_and_still_clean_entries_list + * + * Purpose: In PHDF5, only the metadata cache with mpi rank 0 is allowed + * to write to file. All other metadata caches on processes + * with rank greater than 0 must retain dirty entries until + * they are notified that the entry is now clean. + * + * This function is the main routine for that proceedure. + * It must be called simultaniously on all processes that + * have the relevant file open. To this end, there must + * be a barrier immediately prior to this call. + * + * Typicaly, this will be done one of two ways: + * + * 1) Dirty byte creation exceeds some user specified value. + * + * While metadata reads may occur independently, all + * operations writing metadata must be collective. Thus + * all metadata caches see the same sequence of operations, + * and therefore the same dirty data creation. + * + * This fact is used to synchronize the caches for purposes + * of propagating the list of flushed and still clean + * entries, by simply calling this function from all + * caches whenever some user specified threshold on dirty + * data is exceeded. + * + * 2) Under direct user control -- this operation must be + * collective. + * + * The operations to be managed by this function are as + * follows: + * + * For the process with mpi rank 0: + * + * 1) Enable writes, flush the cache to its min clean size, + * and then disable writes again. + * + * 2) Load the contents of the flushed and still clean entries + * list (c_slist_ptr) into a buffer, and broadcast that + * buffer to all the other caches. + * + * 3) Clear the flushed and still clean entries list + * (c_slist_ptr). + * + * + * For all processes with mpi rank greater than 0: + * + * 1) Receive the flushed and still clean entries list broadcast + * + * 2) Mark the specified entries as clean. + * + * + * For all processes: + * + * 1) Reset the dirtied bytes count to 0. + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: John Mainzer + * July 5, 2005 + * + * Modifications: + * + * JRM -- 5/11/06 + * Added code to call the write_done callback. + * + *------------------------------------------------------------------------- + */ + +#ifdef H5_HAVE_PARALLEL +herr_t +H5AC2_propagate_flushed_and_still_clean_entries_list(H5F_t * f, + hid_t dxpl_id, + H5AC2_t * cache_ptr, + hbool_t do_barrier) +{ + herr_t ret_value = SUCCEED; /* Return value */ + herr_t result; + int mpi_code; + H5AC2_aux_t * aux_ptr = NULL; + + FUNC_ENTER_NOAPI(H5AC2_propagate_flushed_and_still_clean_entries_list, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + + aux_ptr = (H5AC2_aux_t *)(cache_ptr->aux_ptr); + + HDassert( aux_ptr != NULL ); + HDassert( aux_ptr->magic == H5AC2__H5AC2_AUX_T_MAGIC ); + +#if H5AC2_DEBUG_DIRTY_BYTES_CREATION + HDfprintf(stdout, + "%d:H5AC2_propagate...:%d: (u/uu/i/iu/r/ru) = %d/%d/%d/%d/%d/%d\n", + (int)(aux_ptr->mpi_rank), + (int)(aux_ptr->dirty_bytes_propagations), + (int)(aux_ptr->unprotect_dirty_bytes), + (int)(aux_ptr->unprotect_dirty_bytes_updates), + (int)(aux_ptr->insert_dirty_bytes), + (int)(aux_ptr->insert_dirty_bytes_updates), + (int)(aux_ptr->rename_dirty_bytes), + (int)(aux_ptr->rename_dirty_bytes_updates)); +#endif /* H5AC2_DEBUG_DIRTY_BYTES_CREATION */ + + if ( do_barrier ) { + + /* to prevent "messages from the future" we must synchronize all + * processes before we start the flush. This synchronization may + * already be done -- hence the do_barrier parameter. + */ + + if ( MPI_SUCCESS != (mpi_code = MPI_Barrier(aux_ptr->mpi_comm)) ) { + + HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_code) + } + } + + if ( aux_ptr->mpi_rank == 0 ) { + + aux_ptr->write_permitted = TRUE; + + result = H5C2_flush_to_min_clean(cache_ptr, dxpl_id); + + aux_ptr->write_permitted = FALSE; + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "H5C2_flush_to_min_clean() failed.") + } + + if ( aux_ptr->write_done != NULL ) { + + (aux_ptr->write_done)(); + } + + if ( H5AC2_broadcast_clean_list(cache_ptr) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Can't broadcast clean slist.") + } + + HDassert( aux_ptr->c_slist_len == 0 ); + + } else { + + if ( H5AC2_receive_and_apply_clean_list(f, dxpl_id, + cache_ptr) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Can't receive and/or process clean slist broadcast.") + } + } + + aux_ptr->dirty_bytes = 0; +#if H5AC2_DEBUG_DIRTY_BYTES_CREATION + aux_ptr->dirty_bytes_propagations += 1; + aux_ptr->unprotect_dirty_bytes = 0; + aux_ptr->unprotect_dirty_bytes_updates = 0; + aux_ptr->insert_dirty_bytes = 0; + aux_ptr->insert_dirty_bytes_updates = 0; + aux_ptr->rename_dirty_bytes = 0; + aux_ptr->rename_dirty_bytes_updates = 0; +#endif /* H5AC2_DEBUG_DIRTY_BYTES_CREATION */ + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_propagate_flushed_and_still_clean_entries_list() */ +#endif /* H5_HAVE_PARALLEL */ + + +/*------------------------------------------------------------------------- + * + * Function: H5AC2_receive_and_apply_clean_list() + * + * Purpose: Receive the list of cleaned entries from process 0, + * and mark the specified entries as clean. + * + * This function must only be called by the process with + * MPI_rank greater than 0. + * + * Return SUCCEED on success, and FAIL on failure. + * + * Return: Non-negative on success/Negative on failure. + * + * Programmer: John Mainzer, 7/4/05 + * + * Modifications: + * + * JRM --10/24/07 + * Reworked parameter list in support of the revised cache + * API. + * + *------------------------------------------------------------------------- + */ + +#ifdef H5_HAVE_PARALLEL +static herr_t +H5AC2_receive_and_apply_clean_list(H5F_t * f, + hid_t dxpl_id, + H5AC2_t * cache_ptr) +{ + herr_t ret_value = SUCCEED; /* Return value */ + H5AC2_aux_t * aux_ptr = NULL; + haddr_t * haddr_buf_ptr = NULL; + MPI_Offset * MPI_Offset_buf_ptr = NULL; + size_t buf_size; + int i = 0; + int mpi_result; + int num_entries; + + FUNC_ENTER_NOAPI(H5AC2_receive_and_apply_clean_list, FAIL) + + HDassert( cache_ptr != NULL ); + HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); + + aux_ptr = (H5AC2_aux_t *)(cache_ptr->aux_ptr); + + HDassert( aux_ptr != NULL ); + HDassert( aux_ptr->magic == H5AC2__H5AC2_AUX_T_MAGIC ); + HDassert( aux_ptr->mpi_rank != 0 ); + + /* First receive the number of entries in the list so that we + * can set up a buffer to receive them. If there aren't + * any, we are done. + */ + mpi_result = MPI_Bcast(&num_entries, 1, MPI_INT, 0, aux_ptr->mpi_comm); + + if ( mpi_result != MPI_SUCCESS ) { + + HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed 1", mpi_result) + } + + if ( num_entries > 0 ) + { + /* allocate a buffers to store the list of entry base addresses in */ + + buf_size = sizeof(MPI_Offset) * (size_t)num_entries; + + MPI_Offset_buf_ptr = (MPI_Offset *)H5MM_malloc(buf_size); + + if ( MPI_Offset_buf_ptr == NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "memory allocation failed for receive buffer") + } + + haddr_buf_ptr = (haddr_t *)H5MM_malloc(sizeof(haddr_t) * + (size_t)num_entries); + + if ( haddr_buf_ptr == NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "memory allocation failed for haddr buffer") + } + + + /* Now receive the list of cleaned entries + * + * The peculiar structure of the following call to MPI_Bcast is + * due to MPI's (?) failure to believe in the MPI_Offset type. + * Thus the element type is MPI_BYTE, with size equal to the + * buf_size computed above. + */ + + mpi_result = MPI_Bcast((void *)MPI_Offset_buf_ptr, (int)buf_size, + MPI_BYTE, 0, aux_ptr->mpi_comm); + + if ( mpi_result != MPI_SUCCESS ) { + + HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed 2", mpi_result) + } + + + /* translate the MPI_Offsets to haddr_t */ + i = 0; + while ( i < num_entries ) + { + haddr_buf_ptr[i] = H5FD_mpi_MPIOff_to_haddr(MPI_Offset_buf_ptr[i]); + + if ( haddr_buf_ptr[i] == HADDR_UNDEF ) { + + HGOTO_ERROR(H5E_INTERNAL, H5E_BADRANGE, FAIL, \ + "can't convert MPI off to haddr") + } + + i++; + } + + + /* mark the indicated entries as clean */ + if ( H5C2_mark_entries_as_clean(cache_ptr, dxpl_id, + (int32_t)num_entries, + &(haddr_buf_ptr[0])) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Can't mark entries clean.") + + } + } + +done: + + if ( MPI_Offset_buf_ptr != NULL ) { + + MPI_Offset_buf_ptr = + (MPI_Offset *)H5MM_xfree((void *)MPI_Offset_buf_ptr); + } + + if ( haddr_buf_ptr != NULL ) { + + haddr_buf_ptr = (haddr_t *)H5MM_xfree((void *)haddr_buf_ptr); + } + + FUNC_LEAVE_NOAPI(ret_value) + +} /* H5AC2_receive_and_apply_clean_list() */ +#endif /* H5_HAVE_PARALLEL */ + |