/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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:		H5Pdapl.c
 *              October 27, 2008
 *              Neil Fortner <nfortne2@hdfgroup.org>
 *
 * Purpose:		Dataset access property list class routines
 *
 *-------------------------------------------------------------------------
 */

/****************/
/* Module Setup */
/****************/

#include "H5Pmodule.h"          /* This source code file is part of the H5P module */


/***********/
/* Headers */
/***********/
#include "H5private.h"		/* Generic Functions */
#include "H5Dprivate.h"		/* Datasets */
#include "H5Eprivate.h"		/* Error handling */
#include "H5Fprivate.h"		/* Files */
#include "H5Iprivate.h"		/* IDs */
#include "H5Ppkg.h"         /* Property lists */
#include "H5MMprivate.h"	/* Memory management */


/****************/
/* Local Macros */
/****************/

/* ========= Dataset Access properties ============ */
/* Definitions for size of raw data chunk cache(slots) */
#define H5D_ACS_DATA_CACHE_NUM_SLOTS_SIZE       sizeof(size_t)
#define H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF        H5D_CHUNK_CACHE_NSLOTS_DEFAULT
#define H5D_ACS_DATA_CACHE_NUM_SLOTS_ENC        H5P__encode_chunk_cache_nslots
#define H5D_ACS_DATA_CACHE_NUM_SLOTS_DEC        H5P__decode_chunk_cache_nslots
/* Definition for size of raw data chunk cache(bytes) */
#define H5D_ACS_DATA_CACHE_BYTE_SIZE_SIZE       sizeof(size_t)
#define H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF        H5D_CHUNK_CACHE_NBYTES_DEFAULT
#define H5D_ACS_DATA_CACHE_BYTE_SIZE_ENC        H5P__encode_chunk_cache_nbytes
#define H5D_ACS_DATA_CACHE_BYTE_SIZE_DEC        H5P__decode_chunk_cache_nbytes
/* Definition for preemption read chunks first */
#define H5D_ACS_PREEMPT_READ_CHUNKS_SIZE        sizeof(double)
#define H5D_ACS_PREEMPT_READ_CHUNKS_DEF         H5D_CHUNK_CACHE_W0_DEFAULT
#define H5D_ACS_PREEMPT_READ_CHUNKS_ENC         H5P__encode_double
#define H5D_ACS_PREEMPT_READ_CHUNKS_DEC         H5P__decode_double
/* Definitions for VDS view option */
#define H5D_ACS_VDS_VIEW_SIZE                   sizeof(H5D_vds_view_t)
#define H5D_ACS_VDS_VIEW_DEF                    H5D_VDS_LAST_AVAILABLE
#define H5D_ACS_VDS_VIEW_ENC                    H5P__dacc_vds_view_enc
#define H5D_ACS_VDS_VIEW_DEC                    H5P__dacc_vds_view_dec
/* Definitions for VDS printf gap */
#define H5D_ACS_VDS_PRINTF_GAP_SIZE             sizeof(hsize_t)
#define H5D_ACS_VDS_PRINTF_GAP_DEF              (hsize_t)0
#define H5D_ACS_VDS_PRINTF_GAP_ENC              H5P__encode_hsize_t
#define H5D_ACS_VDS_PRINTF_GAP_DEC              H5P__decode_hsize_t
/* Definition for append flush */
#define H5D_ACS_APPEND_FLUSH_SIZE            	sizeof(H5D_append_flush_t)
#define H5D_ACS_APPEND_FLUSH_DEF             	{0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},NULL,NULL}
/* Definitions for external file prefix */
#define H5D_ACS_EFILE_PREFIX_SIZE               sizeof(char *)
#define H5D_ACS_EFILE_PREFIX_DEF                NULL /*default is no prefix */
#define H5D_ACS_EFILE_PREFIX_SET                H5P__dapl_efile_pref_set
#define H5D_ACS_EFILE_PREFIX_GET                H5P__dapl_efile_pref_get
#define H5D_ACS_EFILE_PREFIX_ENC                H5P__dapl_efile_pref_enc
#define H5D_ACS_EFILE_PREFIX_DEC                H5P__dapl_efile_pref_dec
#define H5D_ACS_EFILE_PREFIX_DEL                H5P__dapl_efile_pref_del
#define H5D_ACS_EFILE_PREFIX_COPY               H5P__dapl_efile_pref_copy
#define H5D_ACS_EFILE_PREFIX_CMP                H5P__dapl_efile_pref_cmp
#define H5D_ACS_EFILE_PREFIX_CLOSE              H5P__dapl_efile_pref_close



/******************/
/* Local Typedefs */
/******************/


/********************/
/* Package Typedefs */
/********************/


/********************/
/* Local Prototypes */
/********************/

/* Property class callbacks */
static herr_t H5P__dacc_reg_prop(H5P_genclass_t *pclass);
static herr_t H5P__encode_chunk_cache_nslots(const void *value, void **_pp,
    size_t *size);
static herr_t H5P__decode_chunk_cache_nslots(const void **_pp, void *_value);
static herr_t H5P__encode_chunk_cache_nbytes(const void *value, void **_pp,
    size_t *size);
static herr_t H5P__decode_chunk_cache_nbytes(const void **_pp, void *_value);

/* Property list callbacks */
static herr_t H5P__dacc_vds_view_enc(const void *value, void **pp, size_t *size);
static herr_t H5P__dacc_vds_view_dec(const void **pp, void *value);

/* Property list callbacks */
static herr_t H5P__dapl_efile_pref_set(hid_t prop_id, const char* name, size_t size, void* value);
static herr_t H5P__dapl_efile_pref_get(hid_t prop_id, const char* name, size_t size, void* value);
static herr_t H5P__dapl_efile_pref_enc(const void *value, void **_pp, size_t *size);
static herr_t H5P__dapl_efile_pref_dec(const void **_pp, void *value);
static herr_t H5P__dapl_efile_pref_del(hid_t prop_id, const char* name, size_t size, void* value);
static herr_t H5P__dapl_efile_pref_copy(const char* name, size_t size, void* value);
static int H5P__dapl_efile_pref_cmp(const void *value1, const void *value2, size_t size);
static herr_t H5P__dapl_efile_pref_close(const char* name, size_t size, void* value);


/*********************/
/* Package Variables */
/*********************/

/* Dataset access property list class library initialization object */
const H5P_libclass_t H5P_CLS_DACC[1] = {{
    "dataset access",		/* Class name for debugging     */
    H5P_TYPE_DATASET_ACCESS,    /* Class type                   */

    &H5P_CLS_LINK_ACCESS_g,	/* Parent class                 */
    &H5P_CLS_DATASET_ACCESS_g,	/* Pointer to class             */
    &H5P_CLS_DATASET_ACCESS_ID_g,	/* Pointer to class ID          */
    &H5P_LST_DATASET_ACCESS_ID_g,	/* Pointer to default property list ID */
    H5P__dacc_reg_prop,		/* Default property registration routine */

    NULL,		        /* Class creation callback      */
    NULL,		        /* Class creation callback info */
    NULL,		        /* Class copy callback          */
    NULL,		        /* Class copy callback info     */
    NULL,		        /* Class close callback         */
    NULL 		        /* Class close callback info    */
}};


/*****************************/
/* Library Private Variables */
/*****************************/


/*******************/
/* Local Variables */
/*******************/

/* Property value defaults */
static const H5D_append_flush_t H5D_def_append_flush_g = H5D_ACS_APPEND_FLUSH_DEF;       /* Default setting for append flush */
static const char *H5D_def_efile_prefix_g = H5D_ACS_EFILE_PREFIX_DEF; /* Default external file prefix string */


/*-------------------------------------------------------------------------
 * Function:    H5P__dacc_reg_prop
 *
 * Purpose:     Register the dataset access property list class's
 *              properties
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Neil Fortner
 *              October 27, 2008
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__dacc_reg_prop(H5P_genclass_t *pclass)
{
    size_t rdcc_nslots = H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF;      /* Default raw data chunk cache # of slots */
    size_t rdcc_nbytes = H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF;      /* Default raw data chunk cache # of bytes */
    double rdcc_w0 = H5D_ACS_PREEMPT_READ_CHUNKS_DEF;           /* Default raw data chunk cache dirty ratio */
    H5D_vds_view_t virtual_view = H5D_ACS_VDS_VIEW_DEF;         /* Default VDS view option */
    hsize_t printf_gap = H5D_ACS_VDS_PRINTF_GAP_DEF;            /* Default VDS printf gap */
    herr_t ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_STATIC

    /* Register the size of raw data chunk cache (elements) */
    if(H5P_register_real(pclass, H5D_ACS_DATA_CACHE_NUM_SLOTS_NAME, H5D_ACS_DATA_CACHE_NUM_SLOTS_SIZE, &rdcc_nslots, 
             NULL, NULL, NULL, H5D_ACS_DATA_CACHE_NUM_SLOTS_ENC, H5D_ACS_DATA_CACHE_NUM_SLOTS_DEC, NULL, NULL, NULL, NULL) < 0)
         HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

    /* Register the size of raw data chunk cache(bytes) */
    if(H5P_register_real(pclass, H5D_ACS_DATA_CACHE_BYTE_SIZE_NAME, H5D_ACS_DATA_CACHE_BYTE_SIZE_SIZE, &rdcc_nbytes, 
             NULL, NULL, NULL, H5D_ACS_DATA_CACHE_BYTE_SIZE_ENC, H5D_ACS_DATA_CACHE_BYTE_SIZE_DEC, NULL, NULL, NULL, NULL) < 0)
         HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

    /* Register the preemption for reading chunks */
    if(H5P_register_real(pclass, H5D_ACS_PREEMPT_READ_CHUNKS_NAME, H5D_ACS_PREEMPT_READ_CHUNKS_SIZE, &rdcc_w0, 
             NULL, NULL, NULL, H5D_ACS_PREEMPT_READ_CHUNKS_ENC, H5D_ACS_PREEMPT_READ_CHUNKS_DEC, NULL, NULL, NULL, NULL) < 0)
         HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

    /* Register the VDS view option */
    if(H5P_register_real(pclass, H5D_ACS_VDS_VIEW_NAME, H5D_ACS_VDS_VIEW_SIZE, &virtual_view,
            NULL, NULL, NULL, H5D_ACS_VDS_VIEW_ENC, H5D_ACS_VDS_VIEW_DEC,
            NULL, NULL, NULL, NULL) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

    /* Register the VDS printf gap */
    if(H5P_register_real(pclass, H5D_ACS_VDS_PRINTF_GAP_NAME, H5D_ACS_VDS_PRINTF_GAP_SIZE, &printf_gap,
            NULL, NULL, NULL, H5D_ACS_VDS_PRINTF_GAP_ENC, H5D_ACS_VDS_PRINTF_GAP_DEC,
            NULL, NULL, NULL, NULL) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

    /* Register info for append flush */
    /* (Note: this property should not have an encode/decode callback -QAK) */
    if(H5P_register_real(pclass, H5D_ACS_APPEND_FLUSH_NAME, H5D_ACS_APPEND_FLUSH_SIZE, &H5D_def_append_flush_g, 
             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
         HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

    /* Register property for external file prefix */
    if(H5P_register_real(pclass, H5D_ACS_EFILE_PREFIX_NAME, H5D_ACS_EFILE_PREFIX_SIZE, &H5D_def_efile_prefix_g, 
            NULL, H5D_ACS_EFILE_PREFIX_SET, H5D_ACS_EFILE_PREFIX_GET, H5D_ACS_EFILE_PREFIX_ENC, H5D_ACS_EFILE_PREFIX_DEC,
            H5D_ACS_EFILE_PREFIX_DEL, H5D_ACS_EFILE_PREFIX_COPY, H5D_ACS_EFILE_PREFIX_CMP, H5D_ACS_EFILE_PREFIX_CLOSE) < 0)
         HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P__dacc_reg_prop() */


/*-------------------------------------------------------------------------
 * Function:    H5P__dapl_efile_pref_set
 *
 * Purpose:     Copies an external file prefix property when it's set
 *              for a property list
 *
 * Return:      SUCCEED/FAIL
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__dapl_efile_pref_set(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
    size_t H5_ATTR_UNUSED size, void *value)
{
    FUNC_ENTER_STATIC_NOERR

    /* Sanity check */
    HDassert(value);

    /* Copy the prefix */
    *(char **)value = H5MM_xstrdup(*(const char **)value);

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5P__dapl_efile_pref_set() */


/*-------------------------------------------------------------------------
 * Function:    H5P__dapl_efile_pref_get
 *
 * Purpose:     Copies an external file prefix property when it's retrieved
 *              from a property list
 *
 * Return:      SUCCEED/FAIL
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__dapl_efile_pref_get(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
    size_t H5_ATTR_UNUSED size, void *value)
{
    FUNC_ENTER_STATIC_NOERR

    /* Sanity check */
    HDassert(value);

    /* Copy the prefix */
    *(char **)value = H5MM_xstrdup(*(const char **)value);

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5P__dapl_efile_pref_get() */


/*-------------------------------------------------------------------------
 * Function:    H5P__dapl_efile_pref_enc
 *
 * Purpose:     Callback routine which is called whenever the efile flags
 *              property in the dataset access property list is
 *              encoded.
 *
 * Return:      SUCCEED/FAIL
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__dapl_efile_pref_enc(const void *value, void **_pp, size_t *size)
{
    const char *efile_pref = *(const char * const *)value;
    uint8_t **pp = (uint8_t **)_pp;
    size_t len = 0;
    uint64_t enc_value;
    unsigned enc_size;

    FUNC_ENTER_NOAPI_NOINIT_NOERR

    HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));

    /* calculate prefix length */
    if(NULL != efile_pref)
        len = HDstrlen(efile_pref);

    enc_value = (uint64_t)len;
    enc_size = H5VM_limit_enc_size(enc_value);
    HDassert(enc_size < 256);

    if(NULL != *pp) {
        /* encode the length of the prefix */
        *(*pp)++ = (uint8_t)enc_size;
        UINT64ENCODE_VAR(*pp, enc_value, enc_size);

        /* encode the prefix */
        if(NULL != efile_pref) {
            HDmemcpy(*(char **)pp, efile_pref, len);
            *pp += len;
        } /* end if */
    } /* end if */

    *size += (1 + enc_size);
    if(NULL != efile_pref)
        *size += len;

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5P__dapl_efile_pref_enc() */


/*-------------------------------------------------------------------------
 * Function:    H5P__dapl_efile_pref_dec
 *
 * Purpose:     Callback routine which is called whenever the efile prefix
 *              property in the dataset access property list is
 *              decoded.
 *
 * Return:	    SUCCEED/FAIL
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__dapl_efile_pref_dec(const void **_pp, void *_value)
{
    char **efile_pref = (char **)_value;
    const uint8_t **pp = (const uint8_t **)_pp;
    size_t len;
    uint64_t enc_value;                 /* Decoded property value */
    unsigned enc_size;                  /* Size of encoded property */
    herr_t ret_value = SUCCEED;

    FUNC_ENTER_NOAPI_NOINIT

    HDassert(pp);
    HDassert(*pp);
    HDassert(efile_pref);
    HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));

    /* Decode the size */
    enc_size = *(*pp)++;
    HDassert(enc_size < 256);

    /* Decode the value */
    UINT64DECODE_VAR(*pp, enc_value, enc_size);
    len = (size_t)enc_value;

    if(0 != len) {
        /* Make a copy of the user's prefix string */
        if(NULL == (*efile_pref = (char *)H5MM_malloc(len + 1)))
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "memory allocation failed for prefix")
        HDstrncpy(*efile_pref, *(const char **)pp, len);
        (*efile_pref)[len] = '\0';

        *pp += len;
    } /* end if */
    else
        *efile_pref = NULL;

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P__dapl_efile_pref_dec() */


/*-------------------------------------------------------------------------
 * Function:    H5P__dapl_efile_pref_del
 *
 * Purpose:     Frees memory used to store the external file prefix string
 *
 * Return:      SUCCEED (Can't fail)
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__dapl_efile_pref_del(hid_t H5_ATTR_UNUSED prop_id, const char H5_ATTR_UNUSED *name,
    size_t H5_ATTR_UNUSED size, void *value)
{
    FUNC_ENTER_NOAPI_NOINIT_NOERR

    HDassert(value);

    H5MM_xfree(*(void **)value);

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5P__dapl_efile_pref_del() */


/*-------------------------------------------------------------------------
 * Function:    H5P__dapl_efile_pref_copy
 *
 * Purpose:     Creates a copy of the external file prefix string
 *
 * Return:      SUCCEED/FAIL
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__dapl_efile_pref_copy(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
{
    FUNC_ENTER_NOAPI_NOINIT_NOERR

    HDassert(value);

    *(char **)value = H5MM_xstrdup(*(const char **)value);

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5P__dapl_efile_pref_copy() */


/*-------------------------------------------------------------------------
 * Function:       H5P__dapl_efile_pref_cmp
 *
 * Purpose:        Callback routine which is called whenever the efile prefix
 *                 property in the dataset creation property list is
 *                 compared.
 *
 * Return:         zero if VALUE1 and VALUE2 are equal, non zero otherwise.
 *
 *-------------------------------------------------------------------------
 */
static int
H5P__dapl_efile_pref_cmp(const void *value1, const void *value2, size_t H5_ATTR_UNUSED size)
{
    const char *pref1 = *(const char * const *)value1;
    const char *pref2 = *(const char * const *)value2;
    int ret_value = 0;

    FUNC_ENTER_NOAPI_NOINIT_NOERR

    if(NULL == pref1 && NULL != pref2)
        HGOTO_DONE(1);
    if(NULL != pref1 && NULL == pref2)
        HGOTO_DONE(-1);
    if(NULL != pref1 && NULL != pref2)
        ret_value = HDstrcmp(pref1, pref2);

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P__dapl_efile_pref_cmp() */


/*-------------------------------------------------------------------------
 * Function:    H5P__dapl_efile_pref_close
 *
 * Purpose:     Frees memory used to store the external file prefix string
 *
 * Return:      SUCCEED/FAIL
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__dapl_efile_pref_close(const char H5_ATTR_UNUSED *name, size_t H5_ATTR_UNUSED size, void *value)
{
    FUNC_ENTER_NOAPI_NOINIT_NOERR

    HDassert(value);

    H5MM_xfree(*(void **)value);

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5P__dapl_efile_pref_close() */


/*-------------------------------------------------------------------------
 * Function:	H5Pset_chunk_cache
 *
 * Purpose:	Set the number of objects in the meta data cache and the
 *		maximum number of chunks and bytes in the raw data chunk cache.
 *      Once set, these values will override the values in the file access
 *      property list.  Each of thhese values can be individually unset
 *      (or not set at all) by passing the macros:
 *      H5D_CHUNK_CACHE_NCHUNKS_DEFAULT,
 *      H5D_CHUNK_CACHE_NSLOTS_DEFAULT, and/or
 *      H5D_CHUNK_CACHE_W0_DEFAULT
 *      as appropriate.
 *
 * 		The RDCC_W0 value should be between 0 and 1 inclusive and
 *		indicates how much chunks that have been fully read or fully
 *		written are favored for preemption.  A value of zero means
 *		fully read or written chunks are treated no differently than
 *		other chunks (the preemption is strictly LRU) while a value
 *		of one means fully read chunks are always preempted before
 *		other chunks.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Neil Fortner
 *              Monday, October 27, 2008
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_chunk_cache(hid_t dapl_id, size_t rdcc_nslots, size_t rdcc_nbytes, double rdcc_w0)
{
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value = SUCCEED; /* return value */

    FUNC_ENTER_API(FAIL)
    H5TRACE4("e", "izzd", dapl_id, rdcc_nslots, rdcc_nbytes, rdcc_w0);

    /* Check arguments.  Note that we allow negative values - they are
     * considered to "unset" the property. */
    if(rdcc_w0 > (double)1.0f)
        HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "raw data cache w0 value must be between 0.0 and 1.0 inclusive, or H5D_CHUNK_CACHE_W0_DEFAULT");

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(dapl_id,H5P_DATASET_ACCESS)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID");

    /* Set sizes */
    if(H5P_set(plist, H5D_ACS_DATA_CACHE_NUM_SLOTS_NAME, &rdcc_nslots) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET,FAIL, "can't set data cache number of chunks");
    if(H5P_set(plist, H5D_ACS_DATA_CACHE_BYTE_SIZE_NAME, &rdcc_nbytes) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET,FAIL, "can't set data cache byte size");
    if(H5P_set(plist, H5D_ACS_PREEMPT_READ_CHUNKS_NAME, &rdcc_w0) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET,FAIL, "can't set preempt read chunks");

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pset_chunk_cache() */


/*-------------------------------------------------------------------------
 * Function:	H5Pget_chunk_cache
 *
 * Purpose:	Retrieves the maximum possible number of elements in the meta
 *		data cache and the maximum possible number of elements and
 *		bytes and the RDCC_W0 value in the raw data chunk cache.  Any
 *		(or all) arguments may be null pointers in which case the
 *		corresponding datum is not returned.  If these properties have
 *      not been set on this property list, the default values for a
 *      file access property list are returned.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Neil Fortner
 *              Monday, October 27, 2008
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pget_chunk_cache(hid_t dapl_id, size_t *rdcc_nslots, size_t *rdcc_nbytes, double *rdcc_w0)
{
    H5P_genplist_t *plist;      /* Property list pointer */
    H5P_genplist_t *def_plist;  /* Default file access property list */
    herr_t ret_value = SUCCEED; /* return value */

    FUNC_ENTER_API(FAIL)
    H5TRACE4("e", "i*z*z*d", dapl_id, rdcc_nslots, rdcc_nbytes, rdcc_w0);

    /* Get the plist structure */
    if (NULL == (plist = H5P_object_verify(dapl_id, H5P_DATASET_ACCESS)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID");

    /* Get default file access plist */
    if (NULL == (def_plist = (H5P_genplist_t *)H5I_object(H5P_FILE_ACCESS_DEFAULT)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for default fapl ID");

    /* Get the properties.  If a property is set to the default value, the value
     * from the default fapl is used. */
    if (rdcc_nslots) {
        if (H5P_get(plist, H5D_ACS_DATA_CACHE_NUM_SLOTS_NAME, rdcc_nslots) < 0)
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get data cache number of slots");
        if (*rdcc_nslots == H5D_CHUNK_CACHE_NSLOTS_DEFAULT)
            if (H5P_get(def_plist, H5F_ACS_DATA_CACHE_NUM_SLOTS_NAME, rdcc_nslots) < 0)
                HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get default data cache number of slots");
    } /* end if */
    if (rdcc_nbytes) {
        if (H5P_get(plist, H5D_ACS_DATA_CACHE_BYTE_SIZE_NAME, rdcc_nbytes) < 0)
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get data cache byte size");
        if (*rdcc_nbytes == H5D_CHUNK_CACHE_NBYTES_DEFAULT)
            if (H5P_get(def_plist, H5F_ACS_DATA_CACHE_BYTE_SIZE_NAME, rdcc_nbytes) < 0)
                HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get default data cache byte size");
    } /* end if */
    if (rdcc_w0) {
        if (H5P_get(plist, H5D_ACS_PREEMPT_READ_CHUNKS_NAME, rdcc_w0) < 0)
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get preempt read chunks");
        if (*rdcc_w0 < 0)
            if (H5P_get(def_plist, H5F_ACS_PREEMPT_READ_CHUNKS_NAME, rdcc_w0) < 0)
                HGOTO_ERROR(H5E_PLIST, H5E_CANTGET,FAIL, "can't get default preempt read chunks");
    } /* end if */

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pget_chunk_cache() */


/*-------------------------------------------------------------------------
 * Function:       H5P__encode_chunk_cache_nslots
 *
 * Purpose:        Encode the rdcc_nslots parameter to a serialized
 *                 property list.  Similar to H5P__encode_size_t except
 *                 the value of 255 for the enc_size field is reserved to
 *                 indicate H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF, in which
 *                 nothing further is encoded.
 *
 * Return:         Success:     Non-negative
 *                 Failure:     Negative
 *
 * Programmer:     Neil Fortner
 *                 Wednesday, January 23, 2013
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__encode_chunk_cache_nslots(const void *value, void **_pp, size_t *size)
{
    uint64_t enc_value;     /* Property value to encode */
    uint8_t **pp = (uint8_t **)_pp;
    unsigned enc_size;      /* Size of encoded property */

    FUNC_ENTER_PACKAGE_NOERR

    /* Sanity checks */
    HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
    HDassert(size);

    /* Determine if this is the default value, in which case only encode
     * enc_size (as 255).  Also set size needed for encoding. */
    if(*(const size_t *)value == H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF) {
        enc_size = 0;
        *size += 1;
    } /* end if */
    else {
        enc_value = (uint64_t)*(const size_t *)value;
        enc_size = H5VM_limit_enc_size(enc_value);
        HDassert(enc_size > 0);
        *size += (1 + enc_size);
    } /* end else */

    HDassert(enc_size < 256);

    if(NULL != *pp) {
        /* Encode the size */
        *(*pp)++ = (uint8_t)enc_size;

        /* Encode the value if necessary */
        if(enc_size != 0) {
            UINT64ENCODE_VAR(*pp, enc_value, enc_size);
        } /* end if */
    } /* end if */

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5P__encode_chunk_cache_nslots() */


/*-------------------------------------------------------------------------
 * Function:       H5P__decode_chunk_cache_nslots
 *
 * Purpose:        Decode the rdcc_nslots parameter from a serialized
 *                 property list.  Similar to H5P__decode_size_t except
 *                 the value of 255 for the enc_size field is reserved to
 *                 indicate H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF, in which
 *                 nothing further needs to be decoded.
 *
 * Return:         Success:     Non-negative
 *                 Failure:     Negative
 *
 * Programmer:     Neil Fortner
 *                 Wednesday, January 23, 2013
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__decode_chunk_cache_nslots(const void **_pp, void *_value)
{
    size_t *value = (size_t *)_value;   /* Property value to return */
    const uint8_t **pp = (const uint8_t **)_pp;
    uint64_t enc_value;                 /* Decoded property value */
    unsigned enc_size;                  /* Size of encoded property */

    FUNC_ENTER_PACKAGE_NOERR

    /* Sanity check */
    HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
    HDassert(pp);
    HDassert(*pp);
    HDassert(value);

    /* Decode the size */
    enc_size = *(*pp)++;
    HDassert(enc_size < 256);

    /* Determine if enc_size indicates that this is the default value, in which
     * case set value to H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF and return */
    if(enc_size == 0)
        *value = H5D_ACS_DATA_CACHE_NUM_SLOTS_DEF;
    else {
        /* Decode the value */
        UINT64DECODE_VAR(*pp, enc_value, enc_size);
        H5_CHECKED_ASSIGN(*value, uint64_t, enc_value, size_t);
    } /* end else */

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5P__decode_chunk_cache_nslots() */


/*-------------------------------------------------------------------------
 * Function:       H5P__encode_chunk_cache_nbytes
 *
 * Purpose:        Encode the rdcc_nbytes parameter to a serialized
 *                 property list.  Similar to H5P__encode_size_t except
 *                 the value of 255 for the enc_size field is reserved to
 *                 indicate H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF, in which
 *                 nothing further is encoded.
 *
 * Return:         Success:     Non-negative
 *                 Failure:     Negative
 *
 * Programmer:     Neil Fortner
 *                 Wednesday, January 23, 2013
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__encode_chunk_cache_nbytes(const void *value, void **_pp, size_t *size)
{
    uint64_t enc_value;     /* Property value to encode */
    uint8_t **pp = (uint8_t **)_pp;
    unsigned enc_size;      /* Size of encoded property */

    FUNC_ENTER_PACKAGE_NOERR

    /* Sanity checks */
    HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
    HDassert(size);

    /* Determine if this is the default value, in which case only encode
     * enc_size (as 255).  Also set size needed for encoding. */
    if(*(const size_t *)value == H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF) {
        enc_size = 0;
        *size += 1;
    } /* end if */
    else {
        enc_value = (uint64_t)*(const size_t *)value;
        enc_size = H5VM_limit_enc_size(enc_value);
        HDassert(enc_size > 0);
        *size += (1 + enc_size);
    } /* end else */

    HDassert(enc_size < 256);

    if(NULL != *pp) {
        /* Encode the size */
        *(*pp)++ = (uint8_t)enc_size;

        /* Encode the value if necessary */
        if(enc_size != 0) {
            UINT64ENCODE_VAR(*pp, enc_value, enc_size);
        } /* end if */
    } /* end if */

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5P__encode_chunk_cache_nbytes() */


/*-------------------------------------------------------------------------
 * Function:       H5P__decode_chunk_cache_nbytes
 *
 * Purpose:        Decode the rdcc_nbytes parameter from a serialized
 *                 property list.  Similar to H5P__decode_size_t except
 *                 the value of 255 for the enc_size field is reserved to
 *                 indicate H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF, in which
 *                 nothing further needs to be decoded.
 *
 * Return:         Success:     Non-negative
 *                 Failure:     Negative
 *
 * Programmer:     Neil Fortner
 *                 Wednesday, January 23, 2013
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__decode_chunk_cache_nbytes(const void **_pp, void *_value)
{
    size_t *value = (size_t *)_value;   /* Property value to return */
    const uint8_t **pp = (const uint8_t **)_pp;
    uint64_t enc_value;                 /* Decoded property value */
    unsigned enc_size;                  /* Size of encoded property */

    FUNC_ENTER_PACKAGE_NOERR

    /* Sanity check */
    HDcompile_assert(sizeof(size_t) <= sizeof(uint64_t));
    HDassert(pp);
    HDassert(*pp);
    HDassert(value);

    /* Decode the size */
    enc_size = *(*pp)++;
    HDassert(enc_size < 256);

    /* Determine if enc_size indicates that this is the default value, in which
     * case set value to H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF and return */
    if(enc_size == 0)
        *value = H5D_ACS_DATA_CACHE_BYTE_SIZE_DEF;
    else {
        /* Decode the value */
        UINT64DECODE_VAR(*pp, enc_value, enc_size);
        H5_CHECKED_ASSIGN(*value, uint64_t, enc_value, size_t);
    } /* end else */

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5P__decode_chunk_cache_nbytes() */


/*-------------------------------------------------------------------------
 * Function:    H5Pset_virtual_view
 *
 * Purpose:     Takes the access property list for the virtual dataset,
 *              dapl_id, and the flag, view, and sets the VDS view
 *              according to the flag value.  The view will include all
 *              data before the first missing mapped data found if the
 *              flag is set to H5D_VDS_FIRST_MISSING or to include all
 *              available mapped data if the flag is set to
 *              H5D_VDS_LAST_AVAIALBLE.  Missing mapped data will be
 *              filled with the fill value according to the VDS creation
 *              property settings.  For VDS with unlimited mappings, the
 *              view defines the extent.
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Neil Fortner
 *              May 4, 2015
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_virtual_view(hid_t plist_id, H5D_vds_view_t view)
{
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value = SUCCEED; /* return value */

    FUNC_ENTER_API(FAIL)
    H5TRACE2("e", "iDv", plist_id, view);

    /* Check argument */
    if((view != H5D_VDS_FIRST_MISSING) && (view != H5D_VDS_LAST_AVAILABLE))
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid bounds option")

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Update property list */
    if(H5P_set(plist, H5D_ACS_VDS_VIEW_NAME, &view) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pset_virtual_view() */


/*-------------------------------------------------------------------------
 * Function:    H5Pget_virtual_view
 *
 * Purpose:     Takes the access property list for the virtual dataset,
 *              dapl_id, and gets the flag, view, set by the
 *              H5Pset_virtual_view call.  The possible values of view are
 *              H5D_VDS_FIRST_MISSING or H5D_VDS_LAST_AVAIALBLE. 
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Neil Fortner
 *              May 4, 2015
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pget_virtual_view(hid_t plist_id, H5D_vds_view_t *view)
{
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_API(FAIL)
    H5TRACE2("e", "i*Dv", plist_id, view);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Get value from property list */
    if(view)
        if(H5P_get(plist, H5D_ACS_VDS_VIEW_NAME, view) < 0)
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pget_virtual_view() */


/*-------------------------------------------------------------------------
 * Function:    H5P__dacc_vds_view_enc
 *
 * Purpose:     Callback routine which is called whenever the vds view
 *              property in the dataset access property list is encoded.
 *
 * Return:      Success:        Non-negative
 *              Failure:        Negative
 *
 * Programmer:  Neil Fortner
 *              Tuesday, May 5, 2015
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__dacc_vds_view_enc(const void *value, void **_pp, size_t *size)
{
    const H5D_vds_view_t *view = (const H5D_vds_view_t *)value; /* Create local alias for values */
    uint8_t **pp = (uint8_t **)_pp;

    FUNC_ENTER_STATIC_NOERR

    /* Sanity check */
    HDassert(view);
    HDassert(size);

    if(NULL != *pp)
        /* Encode EDC property */
        *(*pp)++ = (uint8_t)*view;

    /* Size of EDC property */
    (*size)++;

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5P__dacc_vds_view_enc() */


/*-------------------------------------------------------------------------
 * Function:    H5P__dacc_vds_view_dec
 *
 * Purpose:     Callback routine which is called whenever the vds view
 *              property in the dataset access property list is encoded.
 *
 * Return:      Success:        Non-negative
 *              Failure:        Negative
 *
 * Programmer:  Neil Fortner
 *              Tuesday, May 5, 2015
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P__dacc_vds_view_dec(const void **_pp, void *_value)
{
    H5D_vds_view_t *view = (H5D_vds_view_t *)_value;
    const uint8_t **pp = (const uint8_t **)_pp;

    FUNC_ENTER_STATIC_NOERR

    /* Sanity checks */
    HDassert(pp);
    HDassert(*pp);
    HDassert(view);

    /* Decode EDC property */
    *view = (H5D_vds_view_t)*(*pp)++;

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5P__dacc_vds_view_dec() */


/*-------------------------------------------------------------------------
 * Function:    H5Pset_virtual_printf_gap
 *
 * Purpose:     Sets the access property list for the virtual dataset,
 *              dapl_id, to instruct the library to stop looking for the
 *              mapped data stored in the files and/or datasets with the
 *              printf-style names after not finding gap_size files and/or
 *              datasets.  The found source files and datasets will
 *              determine the extent of the unlimited VDS with the printf
 *              -style mappings.
 *
 *              For example, if regularly spaced blocks of VDS are mapped
 *              to datasets with the names d-1, d-2, d-3, ..., d-N, ...,
 *              and d-2 dataset is missing and gap_size is set to 0, then
 *              VDS will contain only data found in d-1.  If d-2 and d-3
 *              are missing and gap_size is set to 2, then VDS will
 *              contain the data from d-1, d-3, ..., d-N, ....  The blocks
 *              that are mapped to d-2 and d-3 will be filled according to
 *              the VDS fill value setting.
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Neil Fortner
 *              May 21, 2015
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_virtual_printf_gap(hid_t plist_id, hsize_t gap_size)
{
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_API(FAIL)
    H5TRACE2("e", "ih", plist_id, gap_size);

    /* Check argument */
    if(gap_size == HSIZE_UNDEF)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid printf gap size")

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Update property list */
    if(H5P_set(plist, H5D_ACS_VDS_PRINTF_GAP_NAME, &gap_size) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to set value")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pset_virtual_printf_gap() */


/*-------------------------------------------------------------------------
 * Function:    H5Pget_virtual_printf_gap
 *
 * Purpose:     Gets the maximum number of missing printf-style files
 *              and/or datasets for determining the extent of the
 *              unlimited VDS, gap_size, using the access property list
 *              for the virtual dataset, dapl_id.  The default library
 *              value for gap_size is 0.
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Neil Fortner
 *              May 21, 2015
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pget_virtual_printf_gap(hid_t plist_id, hsize_t *gap_size)
{
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_API(FAIL)
    H5TRACE2("e", "i*h", plist_id, gap_size);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Get value from property list */
    if(gap_size)
        if(H5P_get(plist, H5D_ACS_VDS_PRINTF_GAP_NAME, gap_size) < 0)
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pget_virtual_printf_gap() */


/*-------------------------------------------------------------------------
 * Function:	H5Pset_append_flush
 *
 * Purpose:	Sets the boundary, callback function, and user data in the
 *		property list.
 *		"ndims": number of array elements for boundary
 *		"boundary": used to determine whether the current dimension hits 
 *			  a boundary; if so, invoke the callback function and
 *			  flush the dataset.
 *		"func": the callback function to invoke when the boundary is hit
 *		"udata": the user data to pass as parameter with the callback function
 *	
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Vailin Choi; Dec 2013
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_append_flush(hid_t plist_id, unsigned ndims, const hsize_t *boundary, H5D_append_cb_t func, void *udata)
{
    H5P_genplist_t *plist;      	/* property list pointer */
    H5D_append_flush_t info;
    unsigned u;				/* local index variable */
    herr_t ret_value = SUCCEED;   	/* return value */

    FUNC_ENTER_API(FAIL)
    H5TRACE5("e", "iIu*hx*x", plist_id, ndims, boundary, func, udata);

    /* Check arguments */
    if(0 == ndims)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dimensionality cannot be zero")
    if(ndims > H5S_MAX_RANK)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dimensionality is too large")
    if(!boundary)
	    HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no boundary dimensions specified")

    /* Check if the callback function is NULL and the user data is non-NULL.
     * This is almost certainly an error as the user data will not be used. */
    if(!func && udata)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback is NULL while user data is not")
 
    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Set up values */
    info.ndims = ndims;
    info.func = func;
    info.udata = udata;

    HDmemset(info.boundary, 0, sizeof(info.boundary));
    /* boundary can be 0 to indicate no boundary is set */
    for(u = 0; u < ndims; u++) {
        if(boundary[u] != (boundary[u] & 0xffffffff)) /* negative value (including H5S_UNLIMITED) */
            HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "all boundary dimensions must be less than 2^32")
        info.boundary[u] = boundary[u]; /* Store user's boundary dimensions */
    } /* end for */

    /* Set values */
    if(H5P_set(plist, H5D_ACS_APPEND_FLUSH_NAME, &info) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set append flush")

done:
    FUNC_LEAVE_API(ret_value)
} /* H5Pset_append_flush() */


/*-------------------------------------------------------------------------
 * Function:	H5Pget_append_flush()
 *
 * Purpose:	Retrieves the boundary, callback function and user data set in 
 *		property list.
 *		Note that the # of boundary sizes to retrieve will not exceed
 *		the parameter "ndims" and the ndims set previously via 
 *		H5Pset_append_flush().
 *	
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Vailin Choi; Dec 2013
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pget_append_flush(hid_t plist_id, unsigned ndims, hsize_t boundary[], H5D_append_cb_t *func, void **udata)
{
    H5P_genplist_t *plist;      /* property list pointer */
    H5D_append_flush_t  info;
    unsigned u;			/* local index variable */
    herr_t ret_value = SUCCEED; /* return value */

    FUNC_ENTER_API(FAIL)
    H5TRACE5("e", "iIu*h*x**x", plist_id, ndims, boundary, func, udata);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Retrieve info for append flush */
    if(H5P_get(plist, H5D_ACS_APPEND_FLUSH_NAME, &info) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object flush callback")

    /* Assign return values */
    if(boundary) {
	HDmemset(boundary, 0, ndims * sizeof(hsize_t));
	if(info.ndims > 0)
	    for(u = 0; u < info.ndims && u < ndims; u++)
		boundary[u] = info.boundary[u];
    } /* end if */
    if(func)
	*func = info.func;
    if(udata)
	*udata = info.udata;

done:
    FUNC_LEAVE_API(ret_value)
} /* H5Pget_append_flush() */


/*-------------------------------------------------------------------------
 * Function:    H5Pset_efile_prefix
 *
 * Purpose:     Set a prefix to be used for any external files.
 *
 *              If the prefix starts with ${ORIGIN}, this will be replaced by
 *              the absolute path of the directory of the HDF5 file containing
 *              the dataset.
 *
 *              If the prefix is ".", no prefix will be applied.
 *
 *              This property can be overwritten by the environment variable
 *              HDF5_EXTFILE_PREFIX.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_efile_prefix(hid_t plist_id, const char *prefix)
{
    H5P_genplist_t *plist;              /* Property list pointer */
    herr_t ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_API(FAIL)
    H5TRACE2("e", "i*s", plist_id, prefix);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Set prefix */
    if(H5P_set(plist, H5D_ACS_EFILE_PREFIX_NAME, &prefix) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set prefix info")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pset_efile_prefix() */


/*-------------------------------------------------------------------------
 * Function:    H5Pget_efile_prefix
 *
 * Purpose:	Gets the prefix to be used for any external files.
 *
 *              If the pointer is not NULL, it points to a user-allocated
 *              buffer.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
ssize_t
H5Pget_efile_prefix(hid_t plist_id, char *prefix, size_t size)
{
    H5P_genplist_t *plist;              /* Property list pointer */
    char *my_prefix;                    /* Library's copy of the prefix */
    size_t	len;                    /* Length of prefix string */
    ssize_t 	ret_value;              /* Return value */

    FUNC_ENTER_API(FAIL)
    H5TRACE3("Zs", "i*sz", plist_id, prefix, size);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_ACCESS)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Get the current prefix */
    if(H5P_peek(plist, H5D_ACS_EFILE_PREFIX_NAME, &my_prefix) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external file prefix")

    /* Check for prefix being set */
    if(my_prefix) {
        /* Copy to user's buffer, if given */
        len = HDstrlen(my_prefix);
        if(prefix) {
            HDstrncpy(prefix, my_prefix, MIN(len + 1, size));
            if(len >= size)
                prefix[size - 1] = '\0';
        } /* end if */
    } /* end if */
    else
        len = 0;

    /* Set return value */
    ret_value = (ssize_t)len;

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pget_efile_prefix() */

