/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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.     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
 *  This program illustrates the usage of HDF5's implicit message sharing
 *  feature, which can be used to save space when the same messages are
 *  used many times in a file.
 *  
 *  This example creates a standard file using file creation property lists
 *  to control which messages are shared.  Messages that can be shared are
 *  datatypes, dataspaces, attributes, fill values, and filter pipelines.
 *  In this example, with messages sharing feature on, the file size is 
 *  reduced by 15%.
 *
 */

#include <stdlib.h>

#include "hdf5.h"

#define NUM_DATASETS 40
const char* DSETNAME[] = {
    "dataset0",    "dataset1",
    "dataset2",    "dataset3",
    "dataset4",    "dataset5",
    "dataset6",    "dataset7",
    "dataset8",    "dataset9",
    "dataset10",   "dataset11",
    "dataset12",   "dataset13",
    "dataset14",   "dataset15",
    "dataset16",   "dataset17",
    "dataset18",   "dataset19",
    "dataset20",   "dataset21",
    "dataset22",   "dataset23",
    "dataset24",   "dataset25",
    "dataset26",   "dataset27",
    "dataset28",   "dataset29",
    "dataset30",   "dataset31",
    "dataset32",   "dataset33",
    "dataset34",   "dataset35",
    "dataset36",   "dataset37",
    "dataset38",   "dataset39",
    NULL
};

herr_t create_standard_file(const char *filename, hid_t fcpl);

/*-------------------------------------------------------------------------
 * Function:    main
 *
 * Purpose:     Enables shared messages using File Creation Property Lists
 *              and creates files using these settings.
 *
 *-------------------------------------------------------------------------
 */
int main(void)
{
    hid_t fcpl_id;
    herr_t ret;

    /* Create a file creation property list */
    fcpl_id = H5Pcreate(H5P_FILE_CREATE);
    if(fcpl_id < 0) goto error;

    /* Create a file without shared message.
     */
    ret = create_standard_file("default_file.h5", fcpl_id);
    if(ret < 0) goto error;

    /* There are five kinds of messages that can be shared: datatypes,
     * dataspaces, attributes, fill values, and filter pipelines.
     * Shared messages are stored in up to five "indexes," this example
     * only uses one index.
     */
    /* To begin with, use only one index. */
    ret = H5Pset_shared_mesg_nindexes(fcpl_id, 1);
    if(ret < 0) goto error;

    /* Each index has a "minimum message size" for a message of that
     * type to be shared.  Since sharing a message creates some overhead,
     * this is to prevent this overhead for very small messages when little
     * space would be saved by sharing them .
     * Let's set the message size to be 40.
     */
    ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_MESG_ALL_FLAG, 40);
    if(ret < 0) goto error;

    /* Each shared message index beins life as a simple list of messages
     * and becomes a B-tree when "too many" messages are written to it.
     * This keeps the indexes simple when only a few messages are shared,
     * but allows them to scale for many messages.  
     * The first value is the maximum list size, the
     * second the minimum B-tree size.
     */
    ret = H5Pset_shared_mesg_phase_change(fcpl_id, 30, 20);
    if(ret < 0) goto error;

    /* Now create a file with shared messages.
     */
    ret = create_standard_file("one_index_file.h5", fcpl_id);
    if(ret < 0) goto error;


    /* Close the property list */
    ret = H5Pclose(fcpl_id);
    if(ret < 0) goto error;
    return 0;

error:
    return -1;
}

/*-------------------------------------------------------------------------
 * Function:    create_standard_file
 *
 * Purpose:     A helper functon for the example.  Creates an HDF5 file
 *              with many repeated messages using the file creation
 *              property list FCPL.
 *
 *              This function only uses datatypes and dataspaces.
 *-------------------------------------------------------------------------
 */
herr_t
create_standard_file(const char *filename, hid_t fcpl_id)
{

    /* First structure  and dataset*/
    typedef struct {
	int    a;
	float  b;
    } s1_t;

    typedef struct  {
        int  c;
        s1_t d;
    } s2_t;
    s2_t       s2[10];
                        
    hid_t      s1_tid,s2_tid;     /* File datatype identifier */


    hid_t file_id=-1;
    hsize_t dims[] = {10}; 
    hid_t space_id=-1;
    hid_t dset_id=-1;
    int i,x;
    herr_t ret;

    /* Create the file */ 
    file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT);
    if(file_id < 0) goto error;

    /* Create the datatype we'll be using.  Generally, sharing messages
     * is most useful when the message is complex and takes more space on
     * disk, so the type in this example will be an compound type rather than an atomic type.
     * However, any type can be shared.
     */
    for( i=0;i<10;i++) {
       s2[i].c=i;
       s2[i].d.a=i+1;
       s2[i].d.b=i*0.6;
    }
    
    /* Create the data type. */

    s1_tid = H5Tcreate (H5T_COMPOUND, sizeof(s1_t));
    H5Tinsert(s1_tid, "inner_int", HOFFSET(s1_t, a), H5T_NATIVE_INT);
    H5Tinsert(s1_tid, "inner_float", HOFFSET(s1_t, b), H5T_NATIVE_FLOAT);
    s2_tid = H5Tcreate (H5T_COMPOUND, sizeof(s2_t));
    H5Tinsert(s2_tid,"outer_int",HOFFSET(s2_t,c),H5T_NATIVE_INT);
    H5Tinsert(s2_tid,"outer_com",HOFFSET(s2_t,d),s1_tid);


    /* Create the dataspace we'll be using.
     */
    space_id = H5Screate_simple(1, dims, NULL);
    if(space_id < 0) goto error;


    /* Begin using the messages many times.  Do this by creating datasets
     * that use this datatype, dataspace.
     */
    for(x = 0; x < NUM_DATASETS; ++x) {
       for( i=0;i<10;i++) {
          s2[i].c=i+x;
          s2[i].d.a=i+x+1;
          s2[i].d.b=(i+x)*0.6;
       }
 
       /* Create a dataset */
       dset_id = H5Dcreate(file_id, DSETNAME[x], s2_tid, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
       if(dset_id < 0) goto error;
       ret = H5Dwrite(dset_id, s2_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, s2);

    }

    ret = H5Tclose(s1_tid);
    if(ret < 0) goto error;
    ret = H5Tclose(s2_tid);
    if(ret < 0) goto error;
    ret = H5Sclose(space_id);
    if(ret < 0) goto error;
    ret = H5Fclose(file_id);
    if(ret < 0) goto error;

    return 0;

error:
    return -1;
}
