/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * 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 COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*-------------------------------------------------------------------------
 *
 * Created:     swmr_common.c
 *
 * Purpose:     Utility functions for the SWMR test code.
 *
 *-------------------------------------------------------------------------
 */

/***********/
/* Headers */
/***********/

#include "h5test.h"
#include "swmr_common.h"
#include "vds_swmr.h"

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

/* The SWMR data arrays:
 *
 * The code uses a 2-D jagged array of datasets.  The first dimension is called
 * the 'level' and there are five of them.
 *
 * #define NLEVELS         5
 *
 * The second dimension is the 'count' and there are quite a few datasets per
 * 'level'.
 *
 * unsigned symbol_count[NLEVELS] = {100, 200, 400, 800, 1600};
 *
 * These datasets are created when the skeleton is generated and are initially
 * empty.  Each dataset has no upper bound on size (H5S_UNLIMITED).  They
 * are of compound type, with two members: an integer ID and an opaque
 * 'data part'.  The data part is not used by the SWMR testing.
 *
 * The SWMR testing will then randomly add and/or remove entries
 * from these datasets.  The selection of the level is skewed by a mapping
 * table which preferentially hammers on the lower levels with their smaller
 * number of datasets.
 *
 * static unsigned symbol_mapping[NMAPPING] = {0, 0, 0, 0, 1, 1, 2, 3, 4};
 *
 * The information about each dataset (name, hid_t, etc.) is stored in a
 * separate array.
 *
 * symbol_info_t *symbol_info[NLEVELS];
 */

/* An array of dataset levels, used to select the level for a SWMR operation
 * Note that this preferentially selects the lower levels with their smaller
 * number of datasets.
 */
static unsigned symbol_mapping[NMAPPING] = {0, 0, 0, 0, 1, 1, 2, 3, 4};

/* The number of datasets at each level */
unsigned symbol_count[NLEVELS] = {100, 200, 400, 800, 1600};

/* Array of dataset information entries (1 per dataset) */
symbol_info_t *symbol_info[NLEVELS];

hsize_t PLANES[N_SOURCES][RANK] = {{1, SM_HEIGHT, WIDTH}, {1, LG_HEIGHT, WIDTH}, {1, SM_HEIGHT, WIDTH},
                                   {1, LG_HEIGHT, WIDTH}, {1, SM_HEIGHT, WIDTH}, {1, LG_HEIGHT, WIDTH}};

char FILE_NAMES[N_SOURCES][NAME_LEN] = {{"vds_swmr_src_a.h5"}, {"vds_swmr_src_b.h5"}, {"vds_swmr_src_c.h5"},
                                        {"vds_swmr_src_d.h5"}, {"vds_swmr_src_e.h5"}, {"vds_swmr_src_f.h5"}};

char VDS_FILE_NAME[NAME_LEN]    = "vds_swmr.h5";
char SOURCE_DSET_PATH[NAME_LEN] = "/source_dset";
char VDS_DSET_NAME[NAME_LEN]    = "vds_dset";

/*-------------------------------------------------------------------------
 * Function:    choose_dataset
 *
 * Purpose:     Selects a random dataset in the SWMR file
 *
 * Parameters:  N/A
 *
 * Return:      Success:    A pointer to information about a dataset.
 *              Failure:    Can't fail
 *
 *-------------------------------------------------------------------------
 */
symbol_info_t *
choose_dataset(void)
{
    unsigned level;  /* The level of the dataset */
    unsigned offset; /* The "offset" of the dataset at that level */

    /* Determine level of dataset */
    level = symbol_mapping[HDrandom() % NMAPPING];

    /* Determine the offset of the level */
    offset = (unsigned)(HDrandom() % (int)symbol_count[level]);

    return &symbol_info[level][offset];
} /* end choose_dataset() */

/*-------------------------------------------------------------------------
 * Function:    create_symbol_datatype
 *
 * Purpose:     Create's the HDF5 datatype used for elements in the SWMR
 *              testing datasets.
 *
 * Parameters:  N/A
 *
 * Return:      Success:    An HDF5 type ID
 *              Failure:    -1
 *
 *-------------------------------------------------------------------------
 */
hid_t
create_symbol_datatype(void)
{
    hid_t sym_type_id;  /* Datatype ID for symbol */
    hid_t opaq_type_id; /* Datatype ID for opaque part of record */

    /* Create opaque datatype to represent other information for this record */
    if ((opaq_type_id = H5Tcreate(H5T_OPAQUE, (size_t)DTYPE_SIZE)) < 0)
        return -1;

    /* Create compound datatype for symbol */
    if ((sym_type_id = H5Tcreate(H5T_COMPOUND, sizeof(symbol_t))) < 0)
        return -1;

    /* Insert fields in symbol datatype */
    if (H5Tinsert(sym_type_id, "rec_id", HOFFSET(symbol_t, rec_id), H5T_NATIVE_UINT64) < 0)
        return -1;
    if (H5Tinsert(sym_type_id, "info", HOFFSET(symbol_t, info), opaq_type_id) < 0)
        return -1;

    /* Close opaque datatype */
    if (H5Tclose(opaq_type_id) < 0)
        return -1;

    return sym_type_id;
} /* end create_symbol_datatype() */

/*-------------------------------------------------------------------------
 * Function:    generate_name
 *
 * Purpose:     Generates a SWMR testing dataset name given a level and
 *              count.
 *              The name is in the format <name>-<level> (%u-%04u).
 *
 * Parameters:  char *name_buf
 *              Buffer for the created name.  Must be pre-allocated.
 *              Since the name is formulaic, this isn't considered an issue.
 *
 *              size_t name_buf_length
 *              The length in bytes of the name_buf buffer
 *
 *              unsigned level
 *              The dataset's level
 *
 *              unsigned count
 *              The dataset's count
 *
 * Return:      Success:    0
 *
 *              Failure:    Can't fail
 *
 *-------------------------------------------------------------------------
 */
int
generate_name(char *name_buf, size_t name_buf_length, unsigned level, unsigned count)
{
    HDassert(name_buf);

    HDsnprintf(name_buf, name_buf_length, "%u-%04u", level, count);

    return 0;
} /* end generate_name() */

/*-------------------------------------------------------------------------
 * Function:    generate_symbols
 *
 * Purpose:     Initializes the global dataset information arrays.
 *
 * Parameters:  N/A
 *
 * Return:      Success:    0
 *              Failure:    Can't fail
 *
 *-------------------------------------------------------------------------
 */
int
generate_symbols(void)
{
    unsigned u, v; /* Local index variables */

    for (u = 0; u < NLEVELS; u++) {
        symbol_info[u] = HDmalloc(symbol_count[u] * sizeof(symbol_info_t));
        for (v = 0; v < symbol_count[u]; v++) {
            char name_buf[64];

            generate_name(name_buf, sizeof(name_buf), u, v);
            symbol_info[u][v].name     = HDstrdup(name_buf);
            symbol_info[u][v].dsid     = -1;
            symbol_info[u][v].nrecords = 0;
        } /* end for */
    }     /* end for */

    return 0;
} /* end generate_symbols() */

/*-------------------------------------------------------------------------
 * Function:    shutdown_symbols
 *
 * Purpose:     Cleans up the global dataset information arrays.
 *
 * Parameters:  N/A
 *
 * Return:      Success:    0
 *              Failure:    Can't fail
 *
 *-------------------------------------------------------------------------
 */
int
shutdown_symbols(void)
{
    unsigned u, v; /* Local index variables */

    /* Clean up the symbols */
    for (u = 0; u < NLEVELS; u++) {
        for (v = 0; v < symbol_count[u]; v++)
            HDfree(symbol_info[u][v].name);
        HDfree(symbol_info[u]);
    } /* end for */

    return 0;
} /* end shutdown_symbols() */

/*-------------------------------------------------------------------------
 * Function:    print_metadata_retries_info
 *
 * Purpose:     To retrieve and print the collection of metadata retries for the file.
 *
 * Parameters:  fid: the currently opened file identifier
 *
 * Return:      Success:    0
 *              Failure:    negative
 *
 *-------------------------------------------------------------------------
 */
int
print_metadata_retries_info(hid_t fid)
{
    H5F_retry_info_t info;
    unsigned         i;

    /* Retrieve the collection of retries */
    if (H5Fget_metadata_read_retry_info(fid, &info) < 0)
        return (-1);

    /* Print information for each non-NULL retries[i] */
    for (i = 0; i < H5F_NUM_METADATA_READ_RETRY_TYPES; i++) {
        unsigned power;
        unsigned j;

        if (NULL == info.retries[i])
            continue;

        HDfprintf(stderr, "Metadata read retries for item %u:\n", i);
        power = 1;
        for (j = 0; j < info.nbins; j++) {
            if (info.retries[i][j])
                HDfprintf(stderr, "\t# of retries for %u - %u retries: %u\n", power, (power * 10) - 1,
                          info.retries[i][j]);
            power *= 10;
        } /* end for */
    }     /* end for */

    /* Free memory for each non-NULL retries[i] */
    for (i = 0; i < H5F_NUM_METADATA_READ_RETRY_TYPES; i++)
        if (info.retries[i] != NULL)
            H5free_memory(info.retries[i]);

    return 0;
} /* print_metadata_retries_info() */
