/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Purpose: Test Shared Object Header Messages */ #include "testhdf5.h" /* * This file needs to access private information from the H5F package. * This file also needs to access the file testing code. */ #define H5F_FRIEND /* suppress error about including H5Fpkg */ #define H5F_TESTING #include "H5Fpkg.h" /* File access */ /* Default SOHM values */ #define DEF_NUM_INDEXES 0 static const unsigned def_type_flags[H5O_SHMESG_MAX_NINDEXES] = {0, 0, 0, 0, 0, 0}; static const unsigned def_minsizes[H5O_SHMESG_MAX_NINDEXES] = {250, 250, 250, 250, 250, 250}; #define DEF_L2B 50 #define DEF_B2L 40 /* Non-default SOHM values for testing */ #define TEST_NUM_INDEXES 4 static const unsigned test_type_flags[H5O_SHMESG_MAX_NINDEXES] = {H5O_SHMESG_FILL_FLAG, H5O_SHMESG_DTYPE_FLAG | H5O_SHMESG_ATTR_FLAG, H5O_SHMESG_SDSPACE_FLAG, H5O_SHMESG_PLINE_FLAG, 0, 0}; static const unsigned test_minsizes[H5O_SHMESG_MAX_NINDEXES] = {0, 2, 40, 100, 3, 1000}; #define TEST_L2B 65 #define TEST_B2L 64 #define FILENAME "tsohm.h5" #define FILENAME_SRC "tsohm_src.h5" #define FILENAME_DST "tsohm_dst.h5" #define NAME_BUF_SIZE 512 /* How much overhead counts as "not much" when converting B-trees, etc. */ #define OVERHEAD_ALLOWED 1.15F #define NUM_DATASETS 10 #define NUM_ATTRIBUTES 100 typedef struct dtype1_struct { int i1; char str[10]; int i2; int i3; int i4; int i5; int i6; int i7; int i8; float f1; } dtype1_struct; #define DTYPE2_SIZE 1024 static const char *DSETNAME[] = {"dataset0", "dataset1", "dataset2", "dataset3", "dataset4", "dataset5", "dataset6", "dataset7", "dataset8", "dataset9", "dataset10", "dataset11", NULL}; static const char *EXTRA_DSETNAME[] = {"ex_dataset0", "ex_dataset1", "ex_dataset2", "ex_dataset3", "ex_dataset4", "ex_dataset5", "ex_dataset6", "ex_dataset7", "ex_dataset8", "ex_dataset9", "ex_dataset10", "ex_dataset11", "ex_dataset12", "ex_dataset13", "ex_dataset14", "ex_dataset15", "ex_dataset16", "ex_dataset17", "ex_dataset18", "ex_dataset19", NULL}; #define SOHM_HELPER_NUM_EX_DSETS 20 typedef struct complex_t { double re; double im; } complex_t; #define ENUM_NUM_MEMBS 20 static const char *ENUM_NAME[] = {"enum_member0", "enum_member1", "enum_member2", "enum_member3", "enum_member4", "enum_member5", "enum_member6", "enum_member7", "enum_member8", "enum_member9", "enum_member10", "enum_member11", "enum_member12", "enum_member13", "enum_member14", "enum_member15", "enum_member16", "enum_member17", "enum_member18", "enum_member19", NULL}; static const int ENUM_VAL[] = {0, 13, -500, 63, 64, -64, 65, 2048, 1, 2, -1, 7, 130, -5000, 630, 640, -640, 650, 20480, 10, -1001, -10}; #define SIZE2_RANK1 6 #define SIZE2_RANK2 10 #define SIZE2_DIMS \ { \ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 \ } #define LONG_STRING \ "00 index. A long string used for testing. To create new strings, set the first two characters to be " \ "some ASCII number other than 00, such as 01." /* Struct returned from size2_helper function */ typedef struct size2_helper_struct { h5_stat_size_t empty_size; h5_stat_size_t first_dset; h5_stat_size_t second_dset; h5_stat_size_t dsets1; h5_stat_size_t dsets2; h5_stat_size_t interleaved; h5_stat_size_t attrs1; h5_stat_size_t attrs2; } size2_helper_struct; /* Number of distinct messages for the sohm_delete test */ #define DELETE_NUM_MESGS 7 #define HALF_DELETE_NUM_MESGS 3 #define DELETE_DIMS \ { \ 1, 1, 1, 1, 1, 1, 1 \ } #define DELETE_MIN_MESG_SIZE 10 #define DELETE_MAX_MESG_SIZE 60 /* Number of dimensions in extend_dset test */ #define EXTEND_NDIMS 2 /* Dimensions for external_dtype test */ #define NX 10 #define NY 10 /* Helper function prototypes */ static hid_t make_dtype_1(void); static hid_t make_dtype_2(void); static hid_t close_reopen_file(hid_t file, const char *filename, hid_t fapl_id); static void test_sohm_attrs(void); #ifdef NOT_NOW static void size2_dump_struct(const char *name, size2_helper_struct *sizes); #endif /* NOT_NOW */ static void size2_verify(void); static void test_sohm_delete(void); static void test_sohm_delete_revert(void); static void test_sohm_extlink(void); /**************************************************************** ** ** verify_fcpl_values(): Verifies that FCPL is set as expected. ** ****************************************************************/ static void verify_fcpl_values(hid_t fcpl_id, const unsigned nindexes_expected, const unsigned *flags_expected, const unsigned *minsizes_expected, unsigned l2b, unsigned b2l) { unsigned nindexes_actual; unsigned list_size; unsigned btree_size; unsigned x; herr_t ret; /* Number of indexes */ ret = H5Pget_shared_mesg_nindexes(fcpl_id, &nindexes_actual); CHECK_I(ret, "H5Pget_shared_mesg_nindexes"); VERIFY(nindexes_actual, nindexes_expected, "H5Pget_shared_mesg_nindexes"); /* Index flags and minsizes */ for (x = 0; x < nindexes_actual; ++x) { unsigned flags_i; unsigned min_mesg_size; ret = H5Pget_shared_mesg_index(fcpl_id, x, &flags_i, &min_mesg_size); CHECK_I(ret, "H5Pget_shared_mesg_index"); VERIFY(flags_i, flags_expected[x], "H5Pget_shared_mesg_index"); VERIFY(min_mesg_size, minsizes_expected[x], "H5Pget_shared_mesg_index"); } /* List-to-btree and btree-to-list values */ ret = H5Pget_shared_mesg_phase_change(fcpl_id, &list_size, &btree_size); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); VERIFY(list_size, l2b, "H5Pset_shared_mesg_phase_change"); VERIFY(btree_size, b2l, "H5Pset_shared_mesg_phase_change"); } /* verify_fcpl_values */ /**************************************************************** ** ** test_sohm_fcpl(): Test File Creation Property Lists. ** ****************************************************************/ static void test_sohm_fcpl(void) { hid_t fid = H5I_INVALID_HID; hid_t fcpl_id = H5I_INVALID_HID; hid_t fcpl2_id = H5I_INVALID_HID; unsigned x; herr_t ret; MESSAGE(5, ("Testing File Creation Properties for Shared Messages\n")); fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); verify_fcpl_values(fcpl_id, DEF_NUM_INDEXES, def_type_flags, def_minsizes, DEF_L2B, DEF_B2L); /* Create a file with this fcpl and make sure that all the values can be * retrieved. */ fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); CHECK_I(fid, "H5Fcreate"); fcpl2_id = H5Fget_create_plist(fid); CHECK_I(fcpl2_id, "H5Fcreate"); verify_fcpl_values(fcpl2_id, DEF_NUM_INDEXES, def_type_flags, def_minsizes, DEF_L2B, DEF_B2L); ret = H5Pclose(fcpl2_id); CHECK_I(ret, "H5Pclose"); /* Close and re-open the file. Make sure that fcpl values are still * correct. */ ret = H5Fclose(fid); CHECK_I(ret, "H5Fclose"); fid = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); CHECK_I(fid, "H5Fopen"); fcpl2_id = H5Fget_create_plist(fid); CHECK_I(ret, "H5Fcreate"); verify_fcpl_values(fcpl2_id, DEF_NUM_INDEXES, def_type_flags, def_minsizes, DEF_L2B, DEF_B2L); /* Clean up */ ret = H5Pclose(fcpl2_id); CHECK_I(ret, "H5Pclose"); ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); ret = H5Fclose(fid); CHECK_I(ret, "H5Fclose"); /* Start over with a non-default fcpl */ fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); /* Set up index values */ ret = H5Pset_shared_mesg_nindexes(fcpl_id, TEST_NUM_INDEXES); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); for (x = 0; x < TEST_NUM_INDEXES; ++x) { ret = H5Pset_shared_mesg_index(fcpl_id, x, test_type_flags[x], test_minsizes[x]); CHECK_I(ret, "H5Pset_shared_mesg_index"); } /* end for */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, TEST_L2B, TEST_B2L); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); verify_fcpl_values(fcpl_id, TEST_NUM_INDEXES, test_type_flags, test_minsizes, TEST_L2B, TEST_B2L); /* Use the fcpl to create a file and get it back again */ fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); CHECK_I(fid, "H5Fcreate"); fcpl2_id = H5Fget_create_plist(fid); CHECK_I(fcpl2_id, "H5Fcreate"); verify_fcpl_values(fcpl2_id, TEST_NUM_INDEXES, test_type_flags, test_minsizes, TEST_L2B, TEST_B2L); ret = H5Pclose(fcpl2_id); CHECK_I(ret, "H5Pclose"); /* Close and re-open the file. Make sure that fcpl values are still * correct. */ ret = H5Fclose(fid); CHECK_I(ret, "H5Fclose"); fid = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); CHECK_I(fid, "H5Fopen"); fcpl2_id = H5Fget_create_plist(fid); CHECK_I(ret, "H5Fcreate"); verify_fcpl_values(fcpl2_id, TEST_NUM_INDEXES, test_type_flags, test_minsizes, TEST_L2B, TEST_B2L); /* Clean up */ ret = H5Pclose(fcpl2_id); CHECK_I(ret, "H5Pclose"); ret = H5Fclose(fid); CHECK_I(ret, "H5Fclose"); /* Actually, the list max can be exactly 1 greater than the * btree min, but no more. * Reset the second index. */ ret = H5Pset_shared_mesg_index(fcpl_id, 1, test_type_flags[1], 15); CHECK_I(ret, "H5Pset_shared_mesg_index"); ret = H5Pset_shared_mesg_phase_change(fcpl_id, 10, 11); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); CHECK_I(fid, "H5Fcreate"); ret = H5Fclose(fid); CHECK_I(ret, "H5Fclose"); /* Test edge cases: * H5O_SHMESG_MAX_NINDEXES and H5O_SHMESG_MAX_LIST_SIZE should be valid * values. * Creating a file with uninitialized indexes should work. (TODO: not implemented?) */ ret = H5Pset_shared_mesg_nindexes(fcpl_id, H5O_SHMESG_MAX_NINDEXES); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_phase_change(fcpl_id, H5O_SHMESG_MAX_LIST_SIZE, H5O_SHMESG_MAX_LIST_SIZE); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); CHECK_I(fid, "H5Fcreate"); /* Clean up */ ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); ret = H5Fclose(fid); CHECK_I(ret, "H5Fclose"); } /* test_sohm_fcpl */ /**************************************************************** ** ** test_sohm_fcpl_errors(): Test bogus FCPL settings for SOHMs ** ****************************************************************/ static void test_sohm_fcpl_errors(void) { hid_t fcpl_id = H5I_INVALID_HID; hid_t fid = H5I_INVALID_HID; unsigned x; herr_t ret; MESSAGE(5, ("Testing bogus file creation properties for shared messages\n")); fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); /* Set up index values */ ret = H5Pset_shared_mesg_nindexes(fcpl_id, TEST_NUM_INDEXES); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); for (x = 0; x < TEST_NUM_INDEXES; ++x) { ret = H5Pset_shared_mesg_index(fcpl_id, x, test_type_flags[x], test_minsizes[x]); CHECK_I(ret, "H5Pset_shared_mesg_index"); } ret = H5Pset_shared_mesg_phase_change(fcpl_id, TEST_L2B, TEST_B2L); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); verify_fcpl_values(fcpl_id, TEST_NUM_INDEXES, test_type_flags, test_minsizes, TEST_L2B, TEST_B2L); H5E_BEGIN_TRY { /* Trying to create too many indexes should fail */ ret = H5Pset_shared_mesg_nindexes(fcpl_id, H5O_SHMESG_MAX_NINDEXES + 1); VERIFY(ret, -1, "H5Pset_shared_mesg_nindexes"); /* Trying to set index to an index higher than the current number * of indexes should fail. */ ret = H5Pset_shared_mesg_index(fcpl_id, H5O_SHMESG_MAX_NINDEXES, 0, 15); VERIFY(ret, -1, "H5Pset_shared_mesg_index"); ret = H5Pset_shared_mesg_index(fcpl_id, TEST_NUM_INDEXES, 0, 15); VERIFY(ret, -1, "H5Pset_shared_mesg_index"); /* Setting an unknown flag (all flags + 1) should fail */ ret = H5Pset_shared_mesg_index(fcpl_id, 1, H5O_SHMESG_ALL_FLAG + 1, 15); VERIFY(ret, -1, "H5Pset_shared_mesg_index"); /* Try setting two different indexes to hold fill messages. They * should hold even very small messages for testing, even though we * wouldn't really want to share such tiny messages in the real world. */ ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_FILL_FLAG, 15); CHECK_I(ret, "H5Pset_shared_mesg_index"); ret = H5Pset_shared_mesg_index(fcpl_id, 1, H5O_SHMESG_FILL_FLAG, 15); CHECK_I(ret, "H5Pset_shared_mesg_index"); fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); VERIFY(fid, -1, "H5Fcreate"); ret = H5Pset_shared_mesg_index(fcpl_id, 1, H5O_SHMESG_DTYPE_FLAG | H5O_SHMESG_FILL_FLAG, 15); CHECK_I(ret, "H5Pset_shared_mesg_index"); fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); VERIFY(fid, -1, "H5Fcreate"); /* Test list/btree cutoffs. We can set these to any positive value, * but if the list max is less than the btree min we'll get an error * when the file is created. */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 10, 12); VERIFY(ret, -1, "H5Pset_shared_mesg_phase_change"); /* Setting them to extremely large values should also fail */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, H5O_SHMESG_MAX_LIST_SIZE + 1, 0); VERIFY(ret, -1, "H5Pset_shared_mesg_phase_change"); ret = H5Pset_shared_mesg_phase_change(fcpl_id, 10, H5O_SHMESG_MAX_LIST_SIZE + 10); VERIFY(ret, -1, "H5Pset_shared_mesg_phase_change"); ret = H5Pset_shared_mesg_phase_change(fcpl_id, H5O_SHMESG_MAX_LIST_SIZE, H5O_SHMESG_MAX_LIST_SIZE + 1); VERIFY(ret, -1, "H5Pset_shared_mesg_phase_change"); } H5E_END_TRY } /* test_sohm_fcpl_errors */ /*------------------------------------------------------------------------- * Function: make_dtype_1 * * Purpose: Creates a complicated datatype for use in testing * shared object header messages. The important thing is that * the datatypes must take a lot of space to store on disk. * * Return: Success: datatype ID (should be closed by calling function) * Failure: negative * *------------------------------------------------------------------------- */ static hid_t make_dtype_1(void) { hid_t dtype1_id = H5I_INVALID_HID; hid_t str_id = H5I_INVALID_HID; /* Create compound datatype. */ if ((dtype1_id = H5Tcreate(H5T_COMPOUND, sizeof(struct dtype1_struct))) < 0) TEST_ERROR; if (H5Tinsert(dtype1_id, "i1", HOFFSET(dtype1_struct, i1), H5T_NATIVE_INT) < 0) TEST_ERROR; str_id = H5Tcopy(H5T_C_S1); if (H5Tset_size(str_id, (size_t)10) < 0) TEST_ERROR; if (H5Tinsert(dtype1_id, "string", HOFFSET(dtype1_struct, str), str_id) < 0) TEST_ERROR; if (H5Tinsert(dtype1_id, "i2", HOFFSET(dtype1_struct, i2), H5T_NATIVE_INT) < 0) TEST_ERROR; if (H5Tinsert(dtype1_id, "i3", HOFFSET(dtype1_struct, i3), H5T_NATIVE_INT) < 0) TEST_ERROR; if (H5Tinsert(dtype1_id, "i4", HOFFSET(dtype1_struct, i4), H5T_NATIVE_INT) < 0) TEST_ERROR; if (H5Tinsert(dtype1_id, "i5", HOFFSET(dtype1_struct, i5), H5T_NATIVE_INT) < 0) TEST_ERROR; if (H5Tinsert(dtype1_id, "i6", HOFFSET(dtype1_struct, i6), H5T_NATIVE_INT) < 0) TEST_ERROR; if (H5Tinsert(dtype1_id, "i7", HOFFSET(dtype1_struct, i7), H5T_NATIVE_INT) < 0) TEST_ERROR; if (H5Tinsert(dtype1_id, "i8", HOFFSET(dtype1_struct, i8), H5T_NATIVE_INT) < 0) TEST_ERROR; if (H5Tinsert(dtype1_id, "f1", HOFFSET(dtype1_struct, f1), H5T_NATIVE_FLOAT) < 0) TEST_ERROR; if (H5Tclose(str_id) < 0) TEST_ERROR; return dtype1_id; error: H5E_BEGIN_TRY { H5Tclose(str_id); H5Tclose(dtype1_id); } H5E_END_TRY return -1; } /* make_dtype1 */ /*------------------------------------------------------------------------- * Function: make_dtype_2 * * Purpose: Creates complicated datatypes for use in testing * shared object header messages. The important thing is that * the datatypes must take a lot of space to store on disk. * * Return: Success: datatype ID (should be closed by calling function) * Failure: negative * *------------------------------------------------------------------------- */ static hid_t make_dtype_2(void) { hid_t dtype2_id = H5I_INVALID_HID; hid_t enum_id = H5I_INVALID_HID; hid_t int_id = H5I_INVALID_HID; int x; hsize_t dims[] = {2, 1, 2, 4}; size_t size; /* Create an int with a strange precision */ if ((int_id = H5Tcopy(H5T_NATIVE_INT)) < 0) TEST_ERROR; if (H5Tset_precision(int_id, (size_t)24) < 0) TEST_ERROR; /* Create an enumeration using that int */ if ((enum_id = H5Tenum_create(int_id)) < 0) TEST_ERROR; for (x = 0; x < ENUM_NUM_MEMBS; x++) if (H5Tenum_insert(enum_id, ENUM_NAME[x], &ENUM_VAL[x]) < 0) TEST_ERROR; /* Create arrays of arrays of arrays of enums */ if ((dtype2_id = H5Tarray_create2(enum_id, 3, dims)) < 0) TEST_ERROR; if ((dtype2_id = H5Tarray_create2(dtype2_id, 4, dims)) < 0) TEST_ERROR; if ((dtype2_id = H5Tarray_create2(dtype2_id, 2, dims)) < 0) TEST_ERROR; if ((dtype2_id = H5Tarray_create2(dtype2_id, 1, dims)) < 0) TEST_ERROR; if (H5Tclose(enum_id) < 0) TEST_ERROR; if (H5Tclose(int_id) < 0) TEST_ERROR; /* Check the datatype size. If this is different than the #defined * size then the fills values will have the wrong size. */ size = H5Tget_size(dtype2_id); if (size != DTYPE2_SIZE) TEST_ERROR; return dtype2_id; error: H5E_BEGIN_TRY { H5Tclose(dtype2_id); H5Tclose(enum_id); H5Tclose(int_id); } H5E_END_TRY return -1; } /* make_dtype2 */ /*------------------------------------------------------------------------- * Function: close_reopen_file * * Purpose: Closes a file and then reopens it. Used to ensure that * SOHMs are written to and read from disk * * Return: Success: new hid_t for the file * Failure: Negative * *------------------------------------------------------------------------- */ static hid_t close_reopen_file(hid_t file, const char *filename, hid_t fapl_id) { if (H5Fclose(file) < 0) FAIL_STACK_ERROR; file = H5Fopen(filename, H5F_ACC_RDWR, fapl_id); if (file < 0) FAIL_STACK_ERROR; return (file); error: return -1; } /* close_reopen_file */ /*------------------------------------------------------------------------- * Function: size1_helper * * Purpose: Creates object headers that use a large datatype message. * * Set test_file_closing to true to add file closing and reopening * whenever possible (to test that SOHMs are written correctly * on disk and not just in memory). * * Return: Success: file ID (may not be the same one passed in) * Failure: H5I_INVALID_HID * *------------------------------------------------------------------------- */ static hid_t size1_helper(hid_t file, const char *filename, hid_t fapl_id, bool test_file_closing) { dtype1_struct wdata; dtype1_struct rdata; hid_t dtype1_id = H5I_INVALID_HID; hid_t space_id = H5I_INVALID_HID; hid_t dset_id = H5I_INVALID_HID; hsize_t dim1[1]; int x; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Macro: TSOHM_S1H_VERIFY_DATA * * Purpose: Encapsulate a common pattern: * Reads the dataset and verifies that [a subset of] the data * are as expected. * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #define TSOHM_S1H_VERIFY_DATA(dset_id, dtype_id) \ { \ memset(&rdata, 0, sizeof(rdata)); \ if (0 > H5Dread((dset_id), (dtype_id), H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdata)) { \ H5_FAILED(); \ AT(); \ printf("Can't read data\n"); \ goto error; \ } \ if ((rdata.i1 != wdata.i1) || (rdata.i2 != wdata.i2) || strcmp(rdata.str, wdata.str) != 0) { \ H5_FAILED(); \ AT(); \ printf("incorrect read data\n"); \ goto error; \ } \ } /* TSOHM_S1H_VERIFY_DATA() definition */ /* Closing and re-opening the file takes a long time on systems without * local disks. Don't close and reopen if express testing is enabled. */ if (GetTestExpress() > 1) test_file_closing = false; /* Initialize wdata */ memset(&wdata, 0, sizeof(wdata)); wdata.i1 = 11; strcpy(wdata.str, "string"); wdata.i2 = 22; wdata.i3 = 33; wdata.i4 = 44; wdata.i5 = 55; wdata.i6 = 66; wdata.i7 = 77; wdata.i8 = 88; wdata.f1 = 0.0F; /* Initialize rdata */ memset(&rdata, 0, sizeof(rdata)); dtype1_id = make_dtype_1(); if (dtype1_id < 0) TEST_ERROR; dim1[0] = 1; space_id = H5Screate_simple(1, dim1, NULL); if (space_id < 0) TEST_ERROR; dset_id = H5Dcreate2(file, DSETNAME[0], dtype1_id, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (dset_id < 0) FAIL_STACK_ERROR; /* Test writing and reading */ if (H5Dwrite(dset_id, dtype1_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, &wdata) < 0) FAIL_STACK_ERROR; TSOHM_S1H_VERIFY_DATA(dset_id, dtype1_id) if (H5Dclose(dset_id) < 0) FAIL_STACK_ERROR; if (test_file_closing) if ((file = close_reopen_file(file, filename, fapl_id)) < 0) TEST_ERROR; /* Create 3 more datasets with the same datatype/dataspace */ for (x = 1; x < 4; x++) { dset_id = H5Dcreate2(file, DSETNAME[x], dtype1_id, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (0 > dset_id) FAIL_STACK_ERROR; if (x == 3) if (H5Dwrite(dset_id, dtype1_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, &wdata) < 0) TEST_ERROR; if (H5Dclose(dset_id) < 0) FAIL_STACK_ERROR; if (test_file_closing) if ((file = close_reopen_file(file, filename, fapl_id)) < 0) TEST_ERROR; } if (H5Tclose(dtype1_id) < 0) TEST_ERROR; /* Make sure the data has been written successfully */ dset_id = H5Dopen2(file, DSETNAME[0], H5P_DEFAULT); if (dset_id < 0) TEST_ERROR; dtype1_id = H5Dget_type(dset_id); if (dtype1_id < 0) TEST_ERROR; TSOHM_S1H_VERIFY_DATA(dset_id, dtype1_id) if (H5Dclose(dset_id) < 0) TEST_ERROR; /* Create several copies of the dataset * this increases the amount of space saved by sharing the datatype message */ for (x = 0; x < SOHM_HELPER_NUM_EX_DSETS; x++) { dset_id = H5Dcreate2(file, EXTRA_DSETNAME[x], dtype1_id, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (dset_id < 0) TEST_ERROR; if (H5Dclose(dset_id) < 0) TEST_ERROR; if (test_file_closing) if ((file = close_reopen_file(file, filename, fapl_id)) < 0) TEST_ERROR; } if (H5Tclose(dtype1_id) < 0) TEST_ERROR; if (H5Sclose(space_id) < 0) TEST_ERROR; /* Ensure that we can still read data back from dataset 3 */ dset_id = H5Dopen2(file, DSETNAME[3], H5P_DEFAULT); if (dset_id < 0) TEST_ERROR; dtype1_id = H5Dget_type(dset_id); if (dtype1_id < 0) TEST_ERROR; TSOHM_S1H_VERIFY_DATA(dset_id, dtype1_id) if (H5Dclose(dset_id) < 0) TEST_ERROR; if (H5Tclose(dtype1_id) < 0) TEST_ERROR; return file; error: H5E_BEGIN_TRY { H5Sclose(space_id); H5Tclose(dtype1_id); H5Dclose(dset_id); H5Fclose(file); } H5E_END_TRY return H5I_INVALID_HID; #undef TSOHM_S1H_VERIFY_DATA /* macro is exclusive to this function */ } /* size1_helper */ /*---------------------------------------------------------------------------- * Function: getsize_testsize1 * * Purpose: Creates a test file, populates it, and returns its file size. * Object header information from the "first" dataset in the file * is stored in pointer `oinfo`. * *---------------------------------------------------------------------------- */ static h5_stat_size_t getsize_testsize1(const char *filename, hid_t fcpl_id, hid_t fapl_id, bool test_file_closing, H5O_native_info_t *ninfo) { hid_t fid = H5I_INVALID_HID; herr_t ret; fid = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl_id, fapl_id); CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); /* If test_file_closing is true, you will get back a different ID, * which will need to be closed. The helper will close your passed-in * ID. */ fid = size1_helper(fid, filename, fapl_id, test_file_closing); CHECK(fid, H5I_INVALID_HID, "size1_helper"); ret = H5Oget_native_info_by_name(fid, DSETNAME[0], ninfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT); CHECK(ret, FAIL, "H5Oget_native_info_by_name"); ret = H5Fclose(fid); CHECK(ret, FAIL, "H5Fclose"); return h5_get_file_size(filename, fapl_id); } /* getsize_testsize1() */ /*------------------------------------------------------------------------- * Function: test_sohm_size1 * * Purpose: Tests shared object header messages with a large datatype * *------------------------------------------------------------------------- */ static void test_sohm_size1(void) { hid_t file = H5I_INVALID_HID; hid_t fcpl_id = H5I_INVALID_HID; hid_t fapl_id = H5I_INVALID_HID; unsigned use_shared = 0; unsigned use_btree = 0; h5_stat_size_t file_sizes[9]; unsigned size_index = 0; hsize_t oh_sizes[3]; unsigned oh_size_index = 0; #if 0 /* TBD: lying comment or bug. See Jira HDFFV-10646 */ hsize_t norm_oh_size; #endif /* Jira HDFFV-10646 */ hsize_t sohm_oh_size; hsize_t sohm_btree_oh_size; h5_stat_size_t norm_empty_filesize; h5_stat_size_t sohm_empty_filesize; h5_stat_size_t sohm_btree_empty_filesize; h5_stat_size_t norm_final_filesize; h5_stat_size_t sohm_final_filesize; h5_stat_size_t sohm_btree_final_filesize; h5_stat_size_t norm_final_filesize2; h5_stat_size_t sohm_final_filesize2; h5_stat_size_t sohm_btree_final_filesize2; H5O_native_info_t ninfo; unsigned num_indexes = 1; unsigned index_flags = H5O_SHMESG_DTYPE_FLAG; unsigned min_mesg_size = 50; unsigned list_max = 11; unsigned btree_min = 10; herr_t ret; MESSAGE(5, ("Testing that shared datatypes save space\n")); /* Create a FAPL with "semi" close degree, to detect dangling IDs */ fapl_id = H5Pcreate(H5P_FILE_ACCESS); CHECK_I(fapl_id, "H5Pcreate"); ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI); CHECK_I(ret, "H5Pset_fclose_degree"); /* ---------------------------------------- * Run operations, accumulating file sizes to compare later. */ for (use_shared = 0; use_shared < 2; use_shared++) { for (use_btree = 0; use_btree < 2; use_btree++) { bool test_open_close; /* cannot use btree indexing without shared messages; skip case */ if (use_btree && !use_shared) continue; fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); if (use_shared) { /* Tests one index holding only datatype messages */ ret = H5Pset_shared_mesg_nindexes(fcpl_id, num_indexes); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 0, index_flags, min_mesg_size); CHECK_I(ret, "H5Pset_shared_mesg_index"); if (use_btree) { ret = H5Pset_shared_mesg_phase_change(fcpl_id, 0, 0); } else { ret = H5Pset_shared_mesg_phase_change(fcpl_id, list_max, btree_min); } CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); } else { ret = H5Pset_shared_mesg_nindexes(fcpl_id, 0); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); } file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, fapl_id); CHECK_I(file, "H5Fcreate"); ret = H5Fclose(file); CHECK_I(ret, "H5Fclose"); /* size of empty file */ file_sizes[size_index++] = h5_get_file_size(FILENAME, fapl_id); /* size of populated file, with different populating behaviors */ test_open_close = true; file_sizes[size_index++] = getsize_testsize1(FILENAME, fcpl_id, fapl_id, test_open_close, &ninfo); test_open_close = false; file_sizes[size_index++] = getsize_testsize1(FILENAME, fcpl_id, fapl_id, test_open_close, &ninfo); oh_sizes[oh_size_index++] = ninfo.hdr.space.total; ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); } /* for btree/listed messages */ } /* for normal/shared messages */ ret = H5Pclose(fapl_id); CHECK_I(ret, "H5Pclose"); /* sanity-check state of arrays */ VERIFY(9, size_index, "size_index"); VERIFY(3, oh_size_index, "oh_size_index"); /* ---------------------------------------- * Check that all sizes make sense. */ /* Put result sizes into human-readable symbolic names. * Order dependent on loop execution above. */ norm_empty_filesize = file_sizes[0]; norm_final_filesize = file_sizes[1]; norm_final_filesize2 = file_sizes[2]; #if 0 /* TBD: lying comment or bug. See Jira HDFFV-10646 */ norm_oh_size = oh_sizes[0]; #endif /* Jira HDFFV-10646 */ sohm_empty_filesize = file_sizes[3]; sohm_final_filesize = file_sizes[4]; sohm_final_filesize2 = file_sizes[5]; sohm_oh_size = oh_sizes[1]; sohm_btree_empty_filesize = file_sizes[6]; sohm_btree_final_filesize = file_sizes[7]; sohm_btree_final_filesize2 = file_sizes[8]; sohm_btree_oh_size = oh_sizes[2]; /* How the SOHM messages are stored shouldn't affect the * size of the object header. */ VERIFY(sohm_btree_oh_size, sohm_oh_size, "H5Oget_info_by_name"); #if 0 /* TBD: lying comment or bug. See Jira HDFFV-10646 */ /* Object headers in SOHM files should be smaller than normal object * headers. */ if (sohm_oh_size >= norm_oh_size) VERIFY(norm_oh_size, 1, "H5Oget_info_by_name"); #endif /* Jira HDFFV-10646 */ /* Both sohm files should be bigger than a normal file when empty. * It's hard to say whether a B-tree with no nodes allocated should be * smaller than a list with SOHM_HELPER_NUM_DTYPES elements. * The sizes here shouldn't really be 1; it's just used to ensure that the * error code triggers. */ if (sohm_empty_filesize <= norm_empty_filesize) VERIFY(sohm_empty_filesize, 1, "h5_get_file_size"); if (sohm_btree_empty_filesize <= norm_empty_filesize) VERIFY(sohm_btree_empty_filesize, 1, "h5_get_file_size"); /* When full, the sohm btree file should be smaller than the normal file. * The sohm list file should be at least as small, since it doesn't need * the overhead of a B-tree. */ if (sohm_btree_final_filesize >= norm_final_filesize) VERIFY(sohm_btree_final_filesize, 1, "h5_get_file_size"); if (sohm_final_filesize > sohm_btree_final_filesize) VERIFY(sohm_final_filesize, 1, "h5_get_file_size"); /* Comparative sizes shouldn't change even if we open and close the file */ if (sohm_btree_final_filesize2 >= norm_final_filesize2) VERIFY(sohm_btree_final_filesize2, 1, "h5_get_file_size"); if (sohm_final_filesize2 > sohm_btree_final_filesize2) VERIFY(sohm_final_filesize2, 1, "h5_get_file_size"); } /* test_sohm_size1 */ /*--------------------------------------------------------------------------- * Function: test_sohm_size_consistency_open_create * * Purpose: Tests that header size is different depending on file open * procedure? * Uses "size1_helper" for file setup directed to a specific * file handle. * *--------------------------------------------------------------------------- */ #if 0 /* TODO: REVEALS BUG TO BE FIXED - SEE JIRA HDFFV-10645 */ static void test_sohm_size_consistency_open_create(void) { hid_t file = H5I_INVALID_HID; hid_t fcpl_id = H5I_INVALID_HID; hid_t fapl_id = H5I_INVALID_HID; unsigned use_btree; hsize_t oh_size_open; hsize_t oh_size_create; H5O_native_info_t oinfo; unsigned num_indexes = 1; unsigned index_flags = H5O_SHMESG_DTYPE_FLAG; unsigned min_mesg_size = 50; unsigned list_max = 11; unsigned btree_min = 10; herr_t ret; MESSAGE(5, \ ("Testing that header size is consistent between H5Fopen and H5Fcreate\n")); /* Create a FAPL with "semi" close degree, to detect dangling IDs */ fapl_id = H5Pcreate(H5P_FILE_ACCESS); CHECK_I(fapl_id, "H5Pcreate"); ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI); CHECK_I(ret, "H5Pset_fclose_degree"); for (use_btree = 0; use_btree < 2; use_btree++) { /* Create FCPL with SOHMs enabled */ fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl_id, num_indexes); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 0, index_flags, min_mesg_size); CHECK_I(ret, "H5Pset_shared_mesg_index"); if (use_btree) { MESSAGE(5, ("----testing with btree index----\n")); ret = H5Pset_shared_mesg_phase_change(fcpl_id, 0, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); } else { MESSAGE(5, ("----testing with normal index----\n")); ret = H5Pset_shared_mesg_phase_change(fcpl_id, list_max, btree_min); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); } /* Create empty file */ file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, fapl_id); CHECK_I(file, "H5Fcreate"); ret = H5Fclose(file); CHECK_I(ret, "H5Fclose"); /* Test Open/Write * Add messages to previously-created file */ file = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl_id); CHECK_I(file, "H5Fopen"); file = size1_helper(file, FILENAME, fapl_id, false); CHECK_I(file, "size1_helper"); /* Get the size of a dataset object header */ ret = H5Oget_native_info_by_name(file, DSETNAME[0], &oinfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT); CHECK_I(ret, "H5Oget_native_info_by_name"); oh_size_open = oinfo.hdr.space.total; ret = H5Fclose(file); CHECK_I(ret, "H5Fclose"); /* Test Create/Write * Add messages to a newly-created file */ file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, fapl_id); CHECK_I(file, "H5Fcreate"); file = size1_helper(file, FILENAME, fapl_id, false); CHECK_I(file, "size1_helper"); /* Get the size of a dataset object header */ ret = H5Oget_native_info_by_name(file, DSETNAME[0], &oinfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT); CHECK_I(ret, "H5Oget_native_info_by_name"); oh_size_create = oinfo.hdr.space.total; ret = H5Fclose(file); CHECK_I(ret, "H5Fclose"); VERIFY(oh_size_create, oh_size_open, "H5Oget_info_by_name2"); ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); } /* for normal/btree indexing */ ret = H5Pclose(fapl_id); CHECK_I(ret, "H5Pclose"); } /* test_sohm_size_consistency_open_create */ #endif /* Jira HDFFV-10645 */ /*------------------------------------------------------------------------- * Function: sohm_attr_helper * * Purpose: Given an fcpl, tests creating attributes with and without * committed datatypes. * Verify that an attribute can be written and read back. * Tests attribute on a Group. * Tests committed and non-committed datatypes. * Tests attribute access through `H5Aopen()`. * *------------------------------------------------------------------------- */ static void sohm_attr_helper(hid_t fcpl_id) { hid_t file_id; hid_t space_id; hsize_t dims = 2; int wdata[2] = {7, 42}; int rdata[2]; herr_t ret; size_t x; unsigned op_index = 0; #define TSOHM_SAH_OP_COUNT 3 const char *groupnames[TSOHM_SAH_OP_COUNT] = { "group_for_nothing_special", "group_for_commited_dtype", "group_for_commited_dtype_and_other_ID_access", }; file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); CHECK_I(file_id, "H5Fcreate"); space_id = H5Screate_simple(1, &dims, &dims); CHECK_I(space_id, "H5Screate_simple"); /* loop: * 0 - nothing special * 1 - committed datatype * 2 - committed datatype, read through second ID */ for (op_index = 0; op_index < TSOHM_SAH_OP_COUNT; op_index++) { hid_t type_id = H5I_INVALID_HID; hid_t group_id = H5I_INVALID_HID; hid_t attr_id = H5I_INVALID_HID; hid_t attr_id2 = H5I_INVALID_HID; hid_t attr_read_id; /* create group in file with name unique to op_index */ group_id = H5Gcreate2(file_id, groupnames[op_index], H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(group_id, "H5Gcreate2"); type_id = H5Tcopy(H5T_NATIVE_INT); CHECK_I(type_id, "H5Tcopy"); /* Commit the datatype for the latter iterations. * Only do this ONCE. */ if (op_index == 1) { ret = H5Tcommit2(file_id, "datatype", type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(ret, "H5Tcommit2"); } attr_id = H5Acreate2(group_id, "attribute", type_id, space_id, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(attr_id, "H5Acreate2"); if (op_index == 2) { /* Open the attribute to get another handle */ attr_id2 = H5Aopen(group_id, "attribute", H5P_DEFAULT); CHECK_I(attr_id2, "H5Aopen"); } ret = H5Awrite(attr_id, H5T_NATIVE_INT, wdata); CHECK_I(ret, "H5Awrite"); ret = H5Gclose(group_id); CHECK_I(ret, "H5Gclose"); ret = H5Tclose(type_id); CHECK_I(ret, "H5Tclose"); /* Flush the file to force data to be written */ ret = H5Fflush(file_id, H5F_SCOPE_GLOBAL); CHECK_I(ret, "H5Fflush"); /* Verify */ attr_read_id = (op_index == 2) ? attr_id2 : attr_id; memset(rdata, 0, sizeof(rdata)); ret = H5Aread(attr_read_id, H5T_NATIVE_INT, rdata); CHECK_I(ret, "H5Aread"); for (x = 0; x < (size_t)dims; ++x) VERIFY(rdata[x], wdata[x], "H5Aread"); ret = H5Aclose(attr_id); CHECK_I(ret, "H5Aclose"); if (attr_id2 > -1) { ret = H5Aclose(attr_id2); CHECK_I(ret, "H5Aclose"); } } /* for each attribute operation */ ret = H5Sclose(space_id); CHECK_I(ret, "H5Sclose"); ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); #undef TSOHM_SAH_OP_COUNT } /* sohm_attr_helper */ /*------------------------------------------------------------------------- * Function: test_sohm_attrs * * Purpose: Attributes can be shared and can also contain shared * datatype and dataspace messages. Committed datatypes * shouldn't be shared. * * Test permutations of this. * *------------------------------------------------------------------------- */ static void test_sohm_attrs(void) { hid_t bad_fid = H5I_INVALID_HID; hid_t fcpl_id = H5I_INVALID_HID; unsigned i = 0; #define TSOHM_TSA_NFLAGS_1 7 unsigned flags1[TSOHM_TSA_NFLAGS_1] = { H5O_SHMESG_ATTR_FLAG, H5O_SHMESG_SDSPACE_FLAG, H5O_SHMESG_DTYPE_FLAG, H5O_SHMESG_ATTR_FLAG | H5O_SHMESG_SDSPACE_FLAG, H5O_SHMESG_SDSPACE_FLAG | H5O_SHMESG_DTYPE_FLAG, H5O_SHMESG_ATTR_FLAG | H5O_SHMESG_DTYPE_FLAG, H5O_SHMESG_ATTR_FLAG | H5O_SHMESG_SDSPACE_FLAG | H5O_SHMESG_DTYPE_FLAG, }; #define TSOHM_TSA_NFLAGS_2 6 unsigned flags2[TSOHM_TSA_NFLAGS_2][2] = { { H5O_SHMESG_ATTR_FLAG, H5O_SHMESG_SDSPACE_FLAG | H5O_SHMESG_DTYPE_FLAG, }, { H5O_SHMESG_SDSPACE_FLAG, H5O_SHMESG_ATTR_FLAG | H5O_SHMESG_DTYPE_FLAG, }, { H5O_SHMESG_DTYPE_FLAG, H5O_SHMESG_ATTR_FLAG | H5O_SHMESG_SDSPACE_FLAG, }, { H5O_SHMESG_SDSPACE_FLAG | H5O_SHMESG_DTYPE_FLAG, H5O_SHMESG_ATTR_FLAG, }, { H5O_SHMESG_ATTR_FLAG | H5O_SHMESG_DTYPE_FLAG, H5O_SHMESG_SDSPACE_FLAG, }, { H5O_SHMESG_ATTR_FLAG | H5O_SHMESG_SDSPACE_FLAG, H5O_SHMESG_DTYPE_FLAG, }, }; #define TSOHM_TSA_NFLAGS_3 5 unsigned flags3[TSOHM_TSA_NFLAGS_3][3] = { { H5O_SHMESG_ATTR_FLAG, H5O_SHMESG_SDSPACE_FLAG, H5O_SHMESG_DTYPE_FLAG, }, { H5O_SHMESG_DTYPE_FLAG, H5O_SHMESG_ATTR_FLAG, H5O_SHMESG_SDSPACE_FLAG, }, { H5O_SHMESG_SDSPACE_FLAG, H5O_SHMESG_DTYPE_FLAG, H5O_SHMESG_ATTR_FLAG, }, { 0, /* first index does not hold a shared message type? */ H5O_SHMESG_SDSPACE_FLAG | H5O_SHMESG_DTYPE_FLAG, H5O_SHMESG_ATTR_FLAG, }, { 0, /* missing SDSPACE flag */ H5O_SHMESG_DTYPE_FLAG, H5O_SHMESG_ATTR_FLAG, }, }; herr_t ret; MESSAGE(5, ("Testing that shared messages work with attributes\n")); /* No shared messages */ fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl_id, 0); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); sohm_attr_helper(fcpl_id); ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); /* One shared message index */ for (i = 0; i < TSOHM_TSA_NFLAGS_1; i++) { fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl_id, 1); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 0, flags1[i], 2); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); sohm_attr_helper(fcpl_id); ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); } /* two shared message indices */ for (i = 0; i < TSOHM_TSA_NFLAGS_2; i++) { fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl_id, 2); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 0, flags2[i][0], 2); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 1, flags2[i][1], 2); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); sohm_attr_helper(fcpl_id); ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); } /* duplicate flags in separate indices causes problems */ H5E_BEGIN_TRY { fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl_id, 2); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_ATTR_FLAG, 2); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 1, H5O_SHMESG_ATTR_FLAG, 2); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); bad_fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); VERIFY(bad_fid, H5I_INVALID_HID, "H5Fcreate"); ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); } H5E_END_TRY /* three shared message indices */ for (i = 0; i < TSOHM_TSA_NFLAGS_3; i++) { fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl_id, 3); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 0, flags3[i][0], 2); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 1, flags3[i][1], 2); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 2, flags3[i][2], 2); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); sohm_attr_helper(fcpl_id); ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); } #undef TSOHM_TSA_NFLAGS_1 #undef TSOHM_TSA_NFLAGS_2 #undef TSOHM_TSA_NFLAGS_3 } /* test_sohm_attrs */ /*------------------------------------------------------------------------- * Function: size2_verify_plist1 * * Purpose: Verify that the property list passed in is in fact the * same property list used as dcpl1_id in the size2 helper * function. This ensures that the filters can be read. * *------------------------------------------------------------------------- */ static void size2_verify_plist1(hid_t plist) { size_t cd_nelmts; unsigned int cd_value; char name[NAME_BUF_SIZE]; H5Z_filter_t filter; hid_t dtype1_id; dtype1_struct fill1; dtype1_struct fill1_correct; herr_t ret; /* Hardcoded to correspond to dcpl1_id created in size2_helper */ /* Check filters */ cd_nelmts = 1; filter = H5Pget_filter2(plist, 0, NULL, &cd_nelmts, &cd_value, (size_t)NAME_BUF_SIZE, name, NULL); CHECK_I(filter, "H5Pget_filter2"); VERIFY(filter, H5Z_FILTER_SHUFFLE, "H5Pget_filter2"); cd_nelmts = 1; filter = H5Pget_filter2(plist, 1, NULL, &cd_nelmts, &cd_value, (size_t)NAME_BUF_SIZE, name, NULL); CHECK_I(filter, "H5Pget_filter2"); VERIFY(filter, H5Z_FILTER_DEFLATE, "H5Pget_filter2"); VERIFY(cd_value, 1, "H5Pget_filter2"); cd_nelmts = 1; filter = H5Pget_filter2(plist, 2, NULL, &cd_nelmts, &cd_value, (size_t)NAME_BUF_SIZE, name, NULL); CHECK_I(filter, "H5Pget_filter2"); VERIFY(filter, H5Z_FILTER_SHUFFLE, "H5Pget_filter2"); cd_nelmts = 1; filter = H5Pget_filter2(plist, 3, NULL, &cd_nelmts, &cd_value, (size_t)NAME_BUF_SIZE, name, NULL); CHECK_I(filter, "H5Pget_filter2"); VERIFY(filter, H5Z_FILTER_FLETCHER32, "H5Pget_filter2"); /* Check fill value */ dtype1_id = make_dtype_1(); CHECK_I(dtype1_id, "make_dtype_1"); memset(&fill1_correct, '1', sizeof(fill1_correct)); ret = H5Pget_fill_value(plist, dtype1_id, &fill1); CHECK_I(ret, "H5Pget_fill_value"); ret = memcmp(&fill1, &fill1_correct, sizeof(fill1_correct)); VERIFY(ret, 0, "memcmp"); ret = H5Tclose(dtype1_id); CHECK_I(ret, "H5Tclose"); } /* size2_verify_plist1 */ /*------------------------------------------------------------------------- * Function: size2_verify_plist2 * * Purpose: Verify that the property list passed in is in fact the * same property list used as dcpl2_id in the size2 helper * function. This ensures that the filters can be read. * *------------------------------------------------------------------------- */ static void size2_verify_plist2(hid_t plist) { size_t cd_nelmts; unsigned int cd_value; char name[NAME_BUF_SIZE]; H5Z_filter_t filter; hid_t dtype2_id; char fill2[DTYPE2_SIZE]; char fill2_correct[DTYPE2_SIZE]; herr_t ret; /* Hardcoded to correspond to dcpl1_id created in size2_helper */ /* Check filters */ cd_nelmts = 1; filter = H5Pget_filter2(plist, 0, NULL, &cd_nelmts, &cd_value, (size_t)NAME_BUF_SIZE, name, NULL); CHECK_I(filter, "H5Pget_filter2"); VERIFY(filter, H5Z_FILTER_DEFLATE, "H5Pget_filter2"); VERIFY(cd_value, 1, "H5Pget_filter2"); cd_nelmts = 1; filter = H5Pget_filter2(plist, 1, NULL, &cd_nelmts, &cd_value, (size_t)NAME_BUF_SIZE, name, NULL); CHECK_I(filter, "H5Pget_filter2"); VERIFY(filter, H5Z_FILTER_DEFLATE, "H5Pget_filter2"); VERIFY(cd_value, 2, "H5Pget_filter2"); cd_nelmts = 1; filter = H5Pget_filter2(plist, 2, NULL, &cd_nelmts, &cd_value, (size_t)NAME_BUF_SIZE, name, NULL); CHECK_I(filter, "H5Pget_filter2"); VERIFY(filter, H5Z_FILTER_DEFLATE, "H5Pget_filter2"); VERIFY(cd_value, 2, "H5Pget_filter2"); cd_nelmts = 1; filter = H5Pget_filter2(plist, 3, NULL, &cd_nelmts, &cd_value, (size_t)NAME_BUF_SIZE, name, NULL); CHECK_I(filter, "H5Pget_filter2"); VERIFY(filter, H5Z_FILTER_DEFLATE, "H5Pget_filter2"); VERIFY(cd_value, 1, "H5Pget_filter2"); cd_nelmts = 1; filter = H5Pget_filter2(plist, 4, NULL, &cd_nelmts, &cd_value, (size_t)NAME_BUF_SIZE, name, NULL); CHECK_I(filter, "H5Pget_filter2"); VERIFY(filter, H5Z_FILTER_DEFLATE, "H5Pget_filter2"); VERIFY(cd_value, 5, "H5Pget_filter2"); /* Check fill value */ dtype2_id = make_dtype_2(); CHECK_I(dtype2_id, "make_dtype_2"); memset(&fill2_correct, '2', (size_t)DTYPE2_SIZE); ret = H5Pget_fill_value(plist, dtype2_id, &fill2); CHECK_I(ret, "H5Pget_fill_value"); ret = memcmp(&fill2, &fill2_correct, (size_t)DTYPE2_SIZE); VERIFY(ret, 0, "memcmp"); ret = H5Tclose(dtype2_id); CHECK_I(ret, "H5Tclose"); } /* size2_verify_plist2 */ #ifdef NOT_NOW /*------------------------------------------------------------------------- * Function: size2_dump_struct * * Purpose: A debugging function to print the contents of a * size2_helper_struct (which holds the various sizes for a * given file during the size2_helper function). * *------------------------------------------------------------------------- */ static void size2_dump_struct(const char *name, size2_helper_struct *sizes) { puts(name); printf(" empty size: %llu\n", (unsigned long long)sizes->empty_size); printf(" first dataset: %llu \tdelta: %llu\n", (unsigned long long)sizes->first_dset, (unsigned long long)(sizes->first_dset - sizes->empty_size)); printf("second dataset: %llu \tdelta: %llu\n", (unsigned long long)sizes->second_dset, (unsigned long long)(sizes->second_dset - sizes->first_dset)); printf(" dsets 1: %llu \tdelta: %llu\n", (unsigned long long)sizes->dsets1, (unsigned long long)(sizes->dsets1 - sizes->second_dset)); printf(" dsets 2: %llu \tdelta: %llu\n", (unsigned long long)sizes->dsets2, (unsigned long long)(sizes->dsets2 - sizes->dsets1)); printf(" interleaved: %llu \tdelta: %llu\n", (unsigned long long)sizes->interleaved, (unsigned long long)(sizes->interleaved - sizes->dsets2)); printf(" attributes: %llu \tdelta: %llu\n", (unsigned long long)sizes->attrs1, (unsigned long long)(sizes->attrs1 - sizes->interleaved)); printf(" attributes 2: %llu \tdelta: %llu\n", (unsigned long long)sizes->attrs2, (unsigned long long)(sizes->attrs2 - sizes->attrs1)); } /* size2_dump_struct */ #endif /* NOT_NOW */ /*------------------------------------------------------------------------- * Function: size2_helper * * Purpose: A helper function for test_sohm_size2. * * Creates a file using the given fcpl, then creates lots * of different kinds of messages within the file and * returns the size of the file for comparison. * * If test_file_closing is not zero, closes and re-opens * the file after every write. * * Doesn't close the property list. Prints an error message * if there's a failure, but doesn't alter its return value. * *------------------------------------------------------------------------- */ static int size2_helper(hid_t fcpl_id, int test_file_closing, size2_helper_struct *ret_sizes) { hid_t file_id = H5I_INVALID_HID; hid_t dtype1_id = H5I_INVALID_HID; hid_t dtype2_id = H5I_INVALID_HID; hid_t dspace1_id = H5I_INVALID_HID; hid_t dspace2_id = H5I_INVALID_HID; hid_t dcpl1_id = H5I_INVALID_HID; hid_t dcpl2_id = H5I_INVALID_HID; hid_t dset_id = H5I_INVALID_HID; hid_t attr_type_id = H5I_INVALID_HID; hid_t attr_space_id = H5I_INVALID_HID; hid_t attr_id = H5I_INVALID_HID; hid_t group_id = H5I_INVALID_HID; char attr_string1[NAME_BUF_SIZE]; char attr_string2[NAME_BUF_SIZE]; char attr_name[NAME_BUF_SIZE]; int x; herr_t ret; /* Constants used in this function */ const int rank1 = SIZE2_RANK1; const int rank2 = SIZE2_RANK2; const hsize_t dims[SIZE2_RANK2] = SIZE2_DIMS; dtype1_struct fill1; char fill2[DTYPE2_SIZE]; /* Closing and re-opening the file takes a long time on systems without * local disks. Don't close and reopen if express testing is enabled. */ if (GetTestExpress() > 1) test_file_closing = 0; /* Create a file and get its size */ file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); CHECK_I(file_id, "H5Fcreate"); ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); /* Get the file size */ ret_sizes->empty_size = h5_get_file_size(FILENAME, H5P_DEFAULT); /* Re-open the file and set up messages to write */ file_id = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); CHECK_I(file_id, "H5Fopen"); /* Create two large datatype messages */ dtype1_id = make_dtype_1(); CHECK_I(dtype1_id, "make_dtype_1"); dtype2_id = make_dtype_2(); CHECK_I(dtype2_id, "make_dtype_2"); /* Create some large dataspaces */ dspace1_id = H5Screate_simple(rank1, dims, dims); CHECK_I(dspace1_id, "H5Screate_simple"); dspace2_id = H5Screate_simple(rank2, dims, dims); CHECK_I(dspace2_id, "H5Screate_simple"); /* fill1 and fill2 are fill values for the two datatypes. * We'll set them in the DCPL. */ memset(&fill1, '1', sizeof(dtype1_struct)); memset(&fill2, '2', (size_t)DTYPE2_SIZE); dcpl1_id = H5Pcreate(H5P_DATASET_CREATE); CHECK_I(dcpl1_id, "H5Pcreate"); H5Pset_fill_value(dcpl1_id, dtype1_id, &fill1); dcpl2_id = H5Pcreate(H5P_DATASET_CREATE); CHECK_I(dcpl2_id, "H5Pcreate"); H5Pset_fill_value(dcpl2_id, dtype2_id, &fill2); /* Filter messages we'll create by setting them in a DCPL. These * values don't need to make sense, they just need to take up space. */ ret = H5Pset_chunk(dcpl1_id, rank1, dims); CHECK_I(ret, "H5Pset_chunk"); ret = H5Pset_shuffle(dcpl1_id); CHECK_I(ret, "H5Pset_shuffle"); ret = H5Pset_deflate(dcpl1_id, 1); CHECK_I(ret, "H5Pset_deflate"); ret = H5Pset_shuffle(dcpl1_id); CHECK_I(ret, "H5Pset_shuffle"); ret = H5Pset_fletcher32(dcpl1_id); CHECK_I(ret, "H5Pset_fletcher32"); /* Make sure that this property list is what it should be */ size2_verify_plist1(dcpl1_id); /* Second dcpl */ ret = H5Pset_chunk(dcpl2_id, rank2, dims); CHECK_I(ret, "H5Pset_chunk"); ret = H5Pset_deflate(dcpl2_id, 1); CHECK_I(ret, "H5Pset_deflate"); ret = H5Pset_deflate(dcpl2_id, 2); CHECK_I(ret, "H5Pset_deflate"); ret = H5Pset_deflate(dcpl2_id, 2); CHECK_I(ret, "H5Pset_deflate"); ret = H5Pset_deflate(dcpl2_id, 1); CHECK_I(ret, "H5Pset_deflate"); ret = H5Pset_deflate(dcpl2_id, 5); CHECK_I(ret, "H5Pset_deflate"); /* Make sure that this property list is what it should be */ size2_verify_plist2(dcpl2_id); /* Set up attribute data */ memset(attr_string1, 0, (size_t)NAME_BUF_SIZE); memset(attr_string2, 0, (size_t)NAME_BUF_SIZE); strcpy(attr_string1, LONG_STRING); strcpy(attr_string2, LONG_STRING); attr_string2[1] = '1'; /* The second string starts "01 index..." */ /* Set up attribute metadata */ attr_type_id = H5Tcopy(H5T_C_S1); CHECK_I(attr_type_id, "H5Tcopy"); ret = H5Tset_size(attr_type_id, (size_t)NAME_BUF_SIZE); CHECK_I(ret, "H5Tset_size"); attr_space_id = H5Screate_simple(1, dims, dims); CHECK_I(attr_space_id, "H5Screate_simple"); /* Create datasets with a big datatype, dataspace, fill value, * and filter pipeline. */ for (x = 0; x < NUM_DATASETS; ++x) { dset_id = H5Dcreate2(file_id, DSETNAME[x], dtype1_id, dspace1_id, H5P_DEFAULT, dcpl1_id, H5P_DEFAULT); CHECK_I(dset_id, "H5Dcreate2"); attr_id = H5Acreate2(dset_id, "attr_name", attr_type_id, attr_space_id, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(attr_id, "H5Acreate2"); ret = H5Awrite(attr_id, attr_type_id, attr_string1); CHECK_I(ret, "H5Awrite"); ret = H5Aclose(attr_id); CHECK_I(ret, "H5Aclose"); ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); /* Gather extra statistics on first two datasets in file */ if (x < 2) { ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); /* Get the file's size now */ if (x == 0) ret_sizes->first_dset = h5_get_file_size(FILENAME, H5P_DEFAULT); else ret_sizes->second_dset = h5_get_file_size(FILENAME, H5P_DEFAULT); file_id = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); CHECK_I(file_id, "H5Fopen"); } /* end if */ /* Close & reopen file if requested */ else if (test_file_closing) { file_id = close_reopen_file(file_id, FILENAME, H5P_DEFAULT); CHECK_I(file_id, "H5Fopen"); } /* end if */ } /* end for */ /* Close file and get its size now */ ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); ret_sizes->dsets1 = h5_get_file_size(FILENAME, H5P_DEFAULT); /* Create new group filled with datasets that use all different messages */ file_id = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); CHECK_I(file_id, "H5Fopen"); group_id = H5Gcreate2(file_id, "group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(group_id, "H5Gcreate2"); /* Create NUM_DATASETS datasets in the new group */ for (x = 0; x < NUM_DATASETS; ++x) { dset_id = H5Dcreate2(group_id, DSETNAME[x], dtype2_id, dspace2_id, H5P_DEFAULT, dcpl2_id, H5P_DEFAULT); CHECK_I(dset_id, "H5Dcreate2"); attr_id = H5Acreate2(dset_id, "attr_name", attr_type_id, attr_space_id, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(attr_id, "H5Acreate2"); ret = H5Awrite(attr_id, attr_type_id, attr_string2); CHECK_I(ret, "H5Awrite"); ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); ret = H5Aclose(attr_id); CHECK_I(ret, "H5Aclose"); /* Close everything & reopen file if requested */ if (test_file_closing) { ret = H5Gclose(group_id); CHECK_I(ret, "H5Gclose"); file_id = close_reopen_file(file_id, FILENAME, H5P_DEFAULT); CHECK_I(file_id, "H5Fopen"); group_id = H5Gopen2(file_id, "group", H5P_DEFAULT); CHECK_I(group_id, "H5Gopen2"); } } /* Close file and get its size now */ ret = H5Gclose(group_id); CHECK_I(ret, "H5Gclose"); ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); ret_sizes->dsets2 = h5_get_file_size(FILENAME, H5P_DEFAULT); /* Create a new group and interleave writes of datasets types 1 and 2. */ file_id = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); CHECK_I(file_id, "H5Fopen"); group_id = H5Gcreate2(file_id, "interleaved group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(group_id, "H5Gcreate2"); /* Create NUM_DATASETS datasets in the new group */ for (x = 0; x < NUM_DATASETS; x += 2) { dset_id = H5Dcreate2(group_id, DSETNAME[x], dtype1_id, dspace1_id, H5P_DEFAULT, dcpl1_id, H5P_DEFAULT); CHECK_I(dset_id, "H5Dcreate2"); attr_id = H5Acreate2(dset_id, "attr_name", attr_type_id, attr_space_id, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(attr_id, "H5Acreate2"); ret = H5Awrite(attr_id, attr_type_id, attr_string1); CHECK_I(ret, "H5Awrite"); ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); ret = H5Aclose(attr_id); CHECK_I(ret, "H5Aclose"); dset_id = H5Dcreate2(group_id, DSETNAME[x + 1], dtype2_id, dspace2_id, H5P_DEFAULT, dcpl2_id, H5P_DEFAULT); CHECK_I(dset_id, "H5Dcreate2"); attr_id = H5Acreate2(dset_id, "attr_name", attr_type_id, attr_space_id, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(attr_id, "H5Acreate2"); ret = H5Awrite(attr_id, attr_type_id, attr_string2); CHECK_I(ret, "H5Awrite"); ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); ret = H5Aclose(attr_id); CHECK_I(ret, "H5Aclose"); /* Close everything & reopen file if requested */ if (test_file_closing) { ret = H5Gclose(group_id); CHECK_I(ret, "H5Gclose"); file_id = close_reopen_file(file_id, FILENAME, H5P_DEFAULT); CHECK_I(file_id, "H5Fopen"); group_id = H5Gopen2(file_id, "interleaved group", H5P_DEFAULT); CHECK_I(group_id, "H5Gopen2"); } } /* Close file and get its size now */ ret = H5Gclose(group_id); CHECK_I(ret, "H5Gclose"); ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); ret_sizes->interleaved = h5_get_file_size(FILENAME, H5P_DEFAULT); /* Create lots of new attribute messages on the group * (using different strings for the attribute) */ file_id = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); CHECK_I(file_id, "H5Fopen"); group_id = H5Gopen2(file_id, "group", H5P_DEFAULT); CHECK_I(group_id, "H5Gopen2"); strcpy(attr_name, "00 index"); for (x = 0; x < NUM_ATTRIBUTES; ++x) { /* Create a unique name and value for each attribute */ attr_string1[0] = attr_name[0] = (char)((x / 10) + '0'); attr_string1[1] = attr_name[1] = (char)((x % 10) + '0'); /* Create an attribute on the group */ attr_id = H5Acreate2(group_id, attr_name, attr_type_id, attr_space_id, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(attr_id, "H5Acreate2"); ret = H5Awrite(attr_id, attr_type_id, attr_string1); CHECK_I(ret, "H5Awrite"); ret = H5Aclose(attr_id); CHECK_I(ret, "H5Aclose"); /* Close everything & reopen file if requested */ if (test_file_closing) { ret = H5Gclose(group_id); CHECK_I(ret, "H5Gclose"); file_id = close_reopen_file(file_id, FILENAME, H5P_DEFAULT); CHECK_I(file_id, "H5Fopen"); group_id = H5Gopen2(file_id, "group", H5P_DEFAULT); CHECK_I(group_id, "H5Gopen2"); } } /* Close file and get its size now */ ret = H5Gclose(group_id); CHECK_I(ret, "H5Gclose"); ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); ret_sizes->attrs1 = h5_get_file_size(FILENAME, H5P_DEFAULT); /* Create all of the attributes again on the other group */ file_id = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); CHECK_I(file_id, "H5Fopen"); group_id = H5Gopen2(file_id, "interleaved group", H5P_DEFAULT); CHECK_I(group_id, "H5Gopen2"); for (x = 0; x < NUM_ATTRIBUTES; ++x) { /* Create the same name and value for each attribute as before */ attr_string1[0] = attr_name[0] = (char)((x / 10) + '0'); attr_string1[1] = attr_name[1] = (char)((x % 10) + '0'); /* Create an attribute on the group */ attr_id = H5Acreate2(group_id, attr_name, attr_type_id, attr_space_id, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(attr_id, "H5Acreate2"); ret = H5Awrite(attr_id, attr_type_id, attr_string1); CHECK_I(ret, "H5Awrite"); ret = H5Aclose(attr_id); CHECK_I(ret, "H5Aclose"); /* Close everything & reopen file if requested */ if (test_file_closing) { ret = H5Gclose(group_id); CHECK_I(ret, "H5Gclose"); file_id = close_reopen_file(file_id, FILENAME, H5P_DEFAULT); CHECK_I(file_id, "H5Fopen"); group_id = H5Gopen2(file_id, "interleaved group", H5P_DEFAULT); CHECK_I(group_id, "H5Gopen2"); } } /* Close file and get its size now */ ret = H5Gclose(group_id); CHECK_I(ret, "H5Gclose"); ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); ret_sizes->attrs2 = h5_get_file_size(FILENAME, H5P_DEFAULT); /* Close everything */ ret = H5Sclose(attr_space_id); CHECK_I(ret, "H5Sclose"); ret = H5Tclose(attr_type_id); CHECK_I(ret, "H5Sclose"); ret = H5Tclose(dtype1_id); CHECK_I(ret, "H5Tclose"); ret = H5Tclose(dtype2_id); CHECK_I(ret, "H5Tclose"); ret = H5Sclose(dspace1_id); CHECK_I(ret, "H5Sclose"); ret = H5Sclose(dspace2_id); CHECK_I(ret, "H5Sclose"); ret = H5Pclose(dcpl1_id); CHECK_I(ret, "H5Pclose"); ret = H5Pclose(dcpl2_id); CHECK_I(ret, "H5Pclose"); return 0; } /* size2_helper */ /*------------------------------------------------------------------------- * Function: size2_verify * * Purpose: A helper function to verify the file created by size2_helper. * * Runs various tests (not exhaustive) to ensure that the * file FILENAME actually has the structure that size2_helper * should have created. * *------------------------------------------------------------------------- */ static void size2_verify(void) { hid_t file_id = H5I_INVALID_HID; hid_t dset_id = H5I_INVALID_HID; hid_t plist_id = H5I_INVALID_HID; hid_t space_id = H5I_INVALID_HID; hid_t group1_id, group2_id; hid_t attr1_id, attr2_id; hid_t attr_type_id; int x, y; herr_t ret; char attr_string[NAME_BUF_SIZE]; char attr_correct_string[NAME_BUF_SIZE]; char attr_name[NAME_BUF_SIZE]; int ndims; hsize_t dims[SIZE2_RANK2]; hsize_t correct_dims[SIZE2_RANK2] = SIZE2_DIMS; file_id = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); CHECK_I(file_id, "H5Fopen"); /* Verify property lists and dataspaces */ /* Get property lists from first batch of datasets */ for (x = 0; x < NUM_DATASETS; ++x) { dset_id = H5Dopen2(file_id, DSETNAME[x], H5P_DEFAULT); CHECK_I(dset_id, "H5Dopen2"); plist_id = H5Dget_create_plist(dset_id); CHECK_I(plist_id, "H5Dget_create_plist"); size2_verify_plist1(plist_id); ret = H5Pclose(plist_id); CHECK_I(ret, "H5Pclose"); space_id = H5Dget_space(dset_id); CHECK_I(space_id, "H5Dget_space"); ndims = H5Sget_simple_extent_dims(space_id, dims, NULL); CHECK_I(ndims, "H5Sget_simple_extent_dims"); VERIFY(ndims, SIZE2_RANK1, "H5Sget_simple_extent_dims"); for (y = 0; y < ndims; ++y) VERIFY(dims[y], correct_dims[y], "H5Sget_simple_extent_dims"); ret = H5Sclose(space_id); CHECK_I(ret, "H5Sclose"); ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); } /* Get property lists from second batch of datasets */ group1_id = H5Gopen2(file_id, "group", H5P_DEFAULT); CHECK_I(group1_id, "H5Gopen2"); for (x = 0; x < NUM_DATASETS; ++x) { dset_id = H5Dopen2(group1_id, DSETNAME[x], H5P_DEFAULT); CHECK_I(dset_id, "H5Dopen2"); plist_id = H5Dget_create_plist(dset_id); CHECK_I(plist_id, "H5Dget_create_plist"); size2_verify_plist2(plist_id); ret = H5Pclose(plist_id); CHECK_I(ret, "H5Pclose"); space_id = H5Dget_space(dset_id); CHECK_I(space_id, "H5Dget_space"); ndims = H5Sget_simple_extent_dims(space_id, dims, NULL); CHECK_I(ndims, "H5Sget_simple_extent_dims"); VERIFY(ndims, SIZE2_RANK2, "H5Sget_simple_extent_dims"); for (y = 0; y < ndims; ++y) VERIFY(dims[y], correct_dims[y], "H5Sget_simple_extent_dims"); ret = H5Sclose(space_id); CHECK_I(ret, "H5Sclose"); ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); } /* end for */ ret = H5Gclose(group1_id); CHECK_I(ret, "H5Gclose"); /* Get property lists from interleaved group of datasets */ group1_id = H5Gopen2(file_id, "interleaved group", H5P_DEFAULT); CHECK_I(group1_id, "H5Gopen2"); for (x = 0; x < NUM_DATASETS; x += 2) { /* First "type 1" dataset */ dset_id = H5Dopen2(group1_id, DSETNAME[x], H5P_DEFAULT); CHECK_I(dset_id, "H5Dopen2"); plist_id = H5Dget_create_plist(dset_id); CHECK_I(plist_id, "H5Dget_create_plist"); size2_verify_plist1(plist_id); ret = H5Pclose(plist_id); CHECK_I(ret, "H5Pclose"); space_id = H5Dget_space(dset_id); CHECK_I(space_id, "H5Dget_space"); ndims = H5Sget_simple_extent_dims(space_id, dims, NULL); CHECK_I(ndims, "H5Sget_simple_extent_dims"); VERIFY(ndims, SIZE2_RANK1, "H5Sget_simple_extent_dims"); for (y = 0; y < ndims; ++y) VERIFY(dims[y], correct_dims[y], "H5Sget_simple_extent_dims"); ret = H5Sclose(space_id); CHECK_I(ret, "H5Sclose"); ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); /* Second "type 2" dataset */ dset_id = H5Dopen2(group1_id, DSETNAME[x + 1], H5P_DEFAULT); CHECK_I(dset_id, "H5Dopen2"); plist_id = H5Dget_create_plist(dset_id); CHECK_I(plist_id, "H5Dget_create_plist"); size2_verify_plist2(plist_id); ret = H5Pclose(plist_id); CHECK_I(ret, "H5Pclose"); space_id = H5Dget_space(dset_id); CHECK_I(space_id, "H5Dget_space"); ndims = H5Sget_simple_extent_dims(space_id, dims, NULL); CHECK_I(ndims, "H5Sget_simple_extent_dims"); VERIFY(ndims, SIZE2_RANK2, "H5Sget_simple_extent_dims"); for (y = 0; y < ndims; ++y) VERIFY(dims[y], correct_dims[y], "H5Sget_simple_extent_dims"); ret = H5Sclose(space_id); CHECK_I(ret, "H5Sclose"); ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); } /* end for */ ret = H5Gclose(group1_id); CHECK_I(ret, "H5Gclose"); /* Verify attributes */ /* Create attribute data type */ attr_type_id = H5Tcopy(H5T_C_S1); CHECK_I(attr_type_id, "H5Tcopy"); ret = H5Tset_size(attr_type_id, (size_t)NAME_BUF_SIZE); CHECK_I(ret, "H5Tset_size"); /* Read attributes on both groups and verify that they are correct */ group1_id = H5Gopen2(file_id, "group", H5P_DEFAULT); CHECK_I(group1_id, "H5Gopen2"); group2_id = H5Gopen2(file_id, "interleaved group", H5P_DEFAULT); CHECK_I(group2_id, "H5Gopen2"); memset(attr_string, 0, (size_t)NAME_BUF_SIZE); memset(attr_correct_string, 0, (size_t)NAME_BUF_SIZE); strcpy(attr_correct_string, LONG_STRING); strcpy(attr_name, "00 index"); for (x = 0; x < NUM_ATTRIBUTES; ++x) { /* Create the name and correct value for each attribute */ attr_correct_string[0] = attr_name[0] = (char)((x / 10) + '0'); attr_correct_string[1] = attr_name[1] = (char)((x % 10) + '0'); attr1_id = H5Aopen(group1_id, attr_name, H5P_DEFAULT); CHECK_I(attr1_id, "H5Aopen"); attr2_id = H5Aopen(group2_id, attr_name, H5P_DEFAULT); CHECK_I(attr2_id, "H5Aopen"); ret = H5Aread(attr1_id, attr_type_id, attr_string); CHECK_I(ret, "H5Aread"); VERIFY_STR(attr_string, attr_correct_string, "H5Aread"); ret = H5Aread(attr2_id, attr_type_id, attr_string); CHECK_I(ret, "H5Aread"); VERIFY_STR(attr_string, attr_correct_string, "H5Aread"); ret = H5Aclose(attr1_id); CHECK_I(attr1_id, "H5Aclose"); ret = H5Aclose(attr2_id); CHECK_I(attr2_id, "H5Aclose"); } /* Close everything */ ret = H5Tclose(attr_type_id); CHECK_I(ret, "H5Tclose"); ret = H5Gclose(group1_id); CHECK_I(ret, "H5Gclose"); ret = H5Gclose(group2_id); CHECK_I(ret, "H5Gclose"); ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); } /* size2_verify */ /*------------------------------------------------------------------------- * Function: test_sohm_size2 * * Purpose: Tests shared object header messages using size2_helper to * create different kinds of big messages. * * If close_reopen is set, closes and reopens the HDF5 file * repeatedly while writing. * * This test works by first creating FCPLs with various * parameters, then creating a standard file that includes * every kind of message that can be shared using the helper * function size2_helper. The test measures the size of the * file at various points. Once all of the files have been * generated, the test compares the measured sizes of the files. * *------------------------------------------------------------------------- */ static void test_sohm_size2(int close_reopen) { hid_t fcpl_id = H5I_INVALID_HID; /* Sizes for file with no shared messages at all */ size2_helper_struct norm_sizes; /* Sizes for files with all messages in one index */ size2_helper_struct list_index_med, list_index_big; size2_helper_struct btree_index, list_index_small; /* Sizes for files with messages in three different indexes */ size2_helper_struct mult_index_med, mult_index_btree; /* Sizes for files that don't share all kinds of messages */ size2_helper_struct share_some_med, share_some_btree; /* Sizes for files that share different sizes of messages */ size2_helper_struct share_some_toobig_index, share_tiny_index, type_space_index; herr_t ret; if (close_reopen == 0) MESSAGE(5, ("Testing that shared object header messages save space\n")); else MESSAGE(5, ("Testing that shared messages save space when file is closed and reopened\n")); /* Create an fcpl with SOHMs disabled */ fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl_id, 0); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); /* Get the file size & verify its contents */ size2_helper(fcpl_id, close_reopen, &norm_sizes); size2_verify(); ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); /* Create an fcpl with one big index */ fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl_id, 1); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_ALL_FLAG, 20); CHECK_I(ret, "H5Pset_shared_mesg_index"); /* Set the indexes to use a medium-sized list */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 30, 25); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); /* Get the file size & verify its contents */ size2_helper(fcpl_id, close_reopen, &list_index_med); size2_verify(); /* Try making the list really big */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 1000, 900); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); /* Get the file size & verify its contents */ size2_helper(fcpl_id, close_reopen, &list_index_big); size2_verify(); /* Use a B-tree instead of a list */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 0, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); /* Get the file size & verify its contents */ size2_helper(fcpl_id, close_reopen, &btree_index); size2_verify(); /* Use such a small list that it'll become a B-tree */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 10, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); /* Get the file size & verify its contents */ size2_helper(fcpl_id, close_reopen, &list_index_small); size2_verify(); ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); /* Create a new property list that puts messages in different indexes. */ fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl_id, 3); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_SDSPACE_FLAG | H5O_SHMESG_DTYPE_FLAG, 20); CHECK_I(ret, "H5Pset_shared_mesg_index"); ret = H5Pset_shared_mesg_index(fcpl_id, 1, H5O_SHMESG_FILL_FLAG | H5O_SHMESG_PLINE_FLAG, 20); CHECK_I(ret, "H5Pset_shared_mesg_index"); ret = H5Pset_shared_mesg_index(fcpl_id, 2, H5O_SHMESG_ATTR_FLAG, 20); CHECK_I(ret, "H5Pset_shared_mesg_index"); /* Use lists that are the same size as the "medium" list on the previous * run. */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 30, 25); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); /* Get the file size & verify its contents */ size2_helper(fcpl_id, close_reopen, &mult_index_med); size2_verify(); /* Use all B-trees */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 0, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); /* Get the file size & verify its contents */ size2_helper(fcpl_id, close_reopen, &mult_index_btree); size2_verify(); /* Edit the same property list (this should work) and don't share all messages. */ ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_PLINE_FLAG, 20); CHECK_I(ret, "H5Pset_shared_mesg_index"); ret = H5Pset_shared_mesg_index(fcpl_id, 1, H5O_SHMESG_DTYPE_FLAG | H5O_SHMESG_FILL_FLAG, 100000); CHECK_I(ret, "H5Pset_shared_mesg_index"); ret = H5Pset_shared_mesg_index(fcpl_id, 2, H5O_SHMESG_ATTR_FLAG | H5O_SHMESG_SDSPACE_FLAG, 20); CHECK_I(ret, "H5Pset_shared_mesg_index"); /* Use "normal-sized" lists. */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 30, 25); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); /* Get the file size & verify its contents */ size2_helper(fcpl_id, close_reopen, &share_some_med); size2_verify(); /* Use btrees. */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 0, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); /* Get the file size & verify its contents */ size2_helper(fcpl_id, close_reopen, &share_some_btree); size2_verify(); /* Change the second index to hold only gigantic messages. Result should * be the same as the previous file. */ ret = H5Pset_shared_mesg_index(fcpl_id, 1, H5O_SHMESG_DTYPE_FLAG | H5O_SHMESG_FILL_FLAG, 100000); CHECK_I(ret, "H5Pset_shared_mesg_index"); /* Get the file size & verify its contents */ size2_helper(fcpl_id, close_reopen, &share_some_toobig_index); size2_verify(); /* Share even tiny dataspace and datatype messages. This should result in * attribute datatypes being shared. Make this one use "really big" lists. * It turns out that attribute dataspaces are just big enough that it saves * some space to share them, while sharing datatypes creates as much overhead * as one gains from sharing them. */ ret = H5Pset_shared_mesg_nindexes(fcpl_id, 1); ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_DTYPE_FLAG | H5O_SHMESG_SDSPACE_FLAG, 1); ret = H5Pset_shared_mesg_phase_change(fcpl_id, 1000, 900); /* Get the file size & verify its contents */ size2_helper(fcpl_id, close_reopen, &share_tiny_index); size2_verify(); /* Create the same file but don't share the really tiny messages */ ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_DTYPE_FLAG | H5O_SHMESG_SDSPACE_FLAG, 100); ret = H5Pset_shared_mesg_phase_change(fcpl_id, 1000, 900); /* Get the file size & verify its contents */ size2_helper(fcpl_id, close_reopen, &type_space_index); size2_verify(); ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); /* Check that all sizes make sense. There is lots of room for inexact * results here since so many different factors contribute to file size. */ /* Check sizes of all files created using a single index first */ /* The empty size of each file with shared messages enabled should be the * same and should be bigger than a normal file. */ if (norm_sizes.empty_size > list_index_med.empty_size) VERIFY(norm_sizes.empty_size, 1, "h5_get_file_size"); if (list_index_med.empty_size != list_index_big.empty_size) VERIFY(list_index_med.empty_size, list_index_big.empty_size, "h5_get_file_size"); if (list_index_med.empty_size != btree_index.empty_size) VERIFY(list_index_med.empty_size, btree_index.empty_size, "h5_get_file_size"); if (list_index_med.empty_size != list_index_small.empty_size) VERIFY(list_index_med.empty_size, list_index_small.empty_size, "h5_get_file_size"); /* The files with indexes shouldn't be that much bigger than an * empty file. */ if (list_index_med.empty_size > (h5_stat_size_t)((float)norm_sizes.empty_size * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); /* Once one dataset has been created (with one of every kind of message), * the normal file should still be smallest. The very small list * btree_convert should be smaller than the B-tree since it has no * extra overhead. The small list should also be smaller than the B-tree. * The very large list should be much larger than anything else. */ if (norm_sizes.first_dset >= list_index_small.first_dset) VERIFY(norm_sizes.first_dset, 1, "h5_get_file_size"); if (list_index_small.first_dset >= btree_index.first_dset) VERIFY(list_index_small.first_dset, 1, "h5_get_file_size"); if (list_index_med.first_dset >= btree_index.first_dset) VERIFY(btree_index.first_dset, 1, "h5_get_file_size"); if (btree_index.first_dset >= list_index_big.first_dset) VERIFY(list_index_med.first_dset, 1, "h5_get_file_size"); /* Once a few copies of the same dataset have been created, the * very small list shouldn't have become a B-tree yet, so it should * be the smallest file. A larger list should be next, followed * by a B-tree, followed by a normal file, followed by a * list that is too large. */ if (list_index_small.dsets1 >= list_index_med.dsets1) VERIFY(btree_index.dsets1, 1, "h5_get_file_size"); if (list_index_med.dsets1 >= btree_index.dsets1) VERIFY(list_index_med.dsets1, 1, "h5_get_file_size"); if (btree_index.dsets1 >= norm_sizes.dsets1) VERIFY(btree_index.dsets1, 1, "h5_get_file_size"); if (norm_sizes.dsets1 >= list_index_big.dsets1) VERIFY(list_index_big.dsets1, 1, "h5_get_file_size"); /* The size gain should have been the same for each of the lists; * their overhead is fixed. The B-tree should have gained at least * as much, and the normal file more than that. */ if ((list_index_small.dsets1 - list_index_small.first_dset) != (list_index_med.dsets1 - list_index_med.first_dset)) VERIFY(0, 1, "h5_get_file_size"); if ((list_index_med.dsets1 - list_index_med.first_dset) != (list_index_big.dsets1 - list_index_big.first_dset)) VERIFY(0, 1, "h5_get_file_size"); if ((list_index_big.dsets1 - list_index_big.first_dset) > (btree_index.dsets1 - btree_index.first_dset)) VERIFY(0, 1, "h5_get_file_size"); if ((btree_index.dsets1 - btree_index.first_dset) >= (norm_sizes.dsets1 - norm_sizes.first_dset)) VERIFY(0, 1, "h5_get_file_size"); /* Once another kind of each message has been written, the very small list * should convert into a B-tree. Now the list should be smallest, then * the B-trees (although the converted B-tree file may be a little bigger), * then the normal file. The largest list may or may not be bigger than * the normal file. */ if (list_index_med.dsets2 >= btree_index.dsets2) VERIFY(list_index_med.dsets2, 1, "h5_get_file_size"); if (btree_index.dsets2 > (h5_stat_size_t)((float)list_index_small.dsets2 * OVERHEAD_ALLOWED)) VERIFY(btree_index.dsets2, list_index_small.dsets2, "h5_get_file_size"); if (list_index_small.dsets2 >= norm_sizes.dsets2) VERIFY(btree_index.dsets2, 1, "h5_get_file_size"); /* If the small list (now a B-tree) is bigger than the existing B-tree, * it shouldn't be much bigger. * It seems that the small lists tends to be pretty big anyway. Allow * for it to have twice as much overhead. */ if (list_index_small.dsets2 > (h5_stat_size_t)((float)btree_index.dsets2 * OVERHEAD_ALLOWED * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); /* The lists should have grown the least since they share messages and * have no extra overhead. The normal file should have grown more than * either the lists or the B-tree. The B-tree may not have grown more * than the lists, depending on whether it needed to split nodes or not. */ if ((list_index_med.dsets2 - list_index_med.dsets1) != (list_index_big.dsets2 - list_index_big.dsets1)) VERIFY(0, 1, "h5_get_file_size"); if ((list_index_big.dsets2 - list_index_big.dsets1) > (btree_index.dsets2 - btree_index.dsets1)) VERIFY(0, 1, "h5_get_file_size"); if ((btree_index.dsets2 - btree_index.dsets1) >= (norm_sizes.dsets2 - norm_sizes.dsets1)) VERIFY(0, 1, "h5_get_file_size"); /* Interleaving the writes should have no effect on how the messages are * shared. No new messages should be written to the indexes, so the * sohm files will only get a little bit bigger. */ if (list_index_med.interleaved >= btree_index.interleaved) VERIFY(0, 1, "h5_get_file_size"); if (btree_index.interleaved > (h5_stat_size_t)((float)list_index_small.interleaved * OVERHEAD_ALLOWED)) VERIFY(btree_index.interleaved, list_index_small.interleaved, "h5_get_file_size"); if (list_index_small.interleaved >= norm_sizes.interleaved) VERIFY(0, 1, "h5_get_file_size"); /* The lists should still have grown the same amount. The converted * B-tree shouldn't have grown more than the index that was originally * a B-tree (although it might have grown less if there was extra free * space within the file). */ if ((list_index_med.interleaved - list_index_med.dsets2) != (list_index_big.interleaved - list_index_big.dsets2)) VERIFY(0, 1, "h5_get_file_size"); if ((list_index_big.interleaved - list_index_big.dsets2) > (btree_index.interleaved - btree_index.dsets2)) VERIFY(0, 1, "h5_get_file_size"); if ((list_index_small.interleaved - list_index_small.dsets2) > (btree_index.interleaved - btree_index.dsets2)) VERIFY(0, 1, "h5_get_file_size"); if ((btree_index.interleaved - btree_index.dsets2) >= (norm_sizes.interleaved - norm_sizes.dsets2)) VERIFY(0, 1, "h5_get_file_size"); /* After many attributes have been written, both the small and medium lists * should have become B-trees and be about the same size as the index * that started as a B-tree. * Add in OVERHEAD_ALLOWED as a fudge factor here, since the allocation * of file space can be hard to predict. */ if (btree_index.attrs1 > (h5_stat_size_t)((float)list_index_small.attrs1 * OVERHEAD_ALLOWED)) VERIFY(btree_index.attrs1, list_index_small.attrs1, "h5_get_file_size"); if (btree_index.attrs1 > (h5_stat_size_t)((float)list_index_med.attrs1 * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); if (list_index_med.attrs1 > (h5_stat_size_t)((float)btree_index.attrs1 * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); if (list_index_small.attrs1 > (h5_stat_size_t)((float)btree_index.attrs1 * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); /* Neither of the converted lists should be too much bigger than * the index that was originally a B-tree. */ if (list_index_small.attrs1 > (h5_stat_size_t)((float)btree_index.attrs1 * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); if (list_index_med.attrs1 > (h5_stat_size_t)((float)btree_index.attrs1 * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); /* The "normal" file should have had less overhead, so should gain less * size than any of the other indexes since none of these attribute * messages could be shared. The large list should have gained * less overhead than the B-tree indexes. */ if ((norm_sizes.attrs1 - norm_sizes.interleaved) >= (list_index_big.attrs1 - list_index_big.interleaved)) VERIFY(0, 1, "h5_get_file_size"); if ((list_index_big.attrs1 - list_index_big.interleaved) >= (list_index_small.attrs1 - list_index_small.interleaved)) VERIFY(0, 1, "h5_get_file_size"); /* Give it some overhead (for checkin to move messages into continuation message) */ if ((list_index_small.attrs1 - list_index_small.interleaved) > (h5_stat_size_t)((float)(btree_index.attrs1 - btree_index.interleaved) * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); /* Writing another copy of each attribute shouldn't change the ordering * of sizes. The big list index is still too big to be smaller than a * normal file. The B-tree indexes should all be about the same size. */ if (btree_index.attrs2 > (h5_stat_size_t)((float)list_index_small.attrs2 * OVERHEAD_ALLOWED)) VERIFY(btree_index.attrs2, list_index_small.attrs2, "h5_get_file_size"); if (list_index_small.attrs2 > (h5_stat_size_t)((float)btree_index.attrs2 * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); if (btree_index.attrs2 > (h5_stat_size_t)((float)list_index_med.attrs2 * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); if (list_index_med.attrs2 > (h5_stat_size_t)((float)btree_index.attrs2 * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); if (list_index_med.attrs2 >= norm_sizes.attrs2) VERIFY(0, 1, "h5_get_file_size"); if (list_index_big.attrs2 >= norm_sizes.attrs2) VERIFY(0, 1, "h5_get_file_size"); /* All of the B-tree indexes should have gained about the same amount * of space; at least as much as the list index and less than a normal * file. */ if ((list_index_small.attrs2 - list_index_small.attrs1) > (btree_index.attrs2 - btree_index.attrs1)) VERIFY(0, 1, "h5_get_file_size"); if ((list_index_med.attrs2 - list_index_med.attrs1) > (btree_index.attrs2 - btree_index.attrs1)) VERIFY(0, 1, "h5_get_file_size"); if ((list_index_big.attrs2 - list_index_big.attrs1) > (list_index_med.attrs2 - list_index_med.attrs1)) VERIFY(0, 1, "h5_get_file_size"); if ((btree_index.attrs2 - btree_index.attrs1) >= (norm_sizes.attrs2 - norm_sizes.attrs1)) VERIFY(0, 1, "h5_get_file_size"); /* Done checking the first few files that use a single index. */ /* Start comparing other kinds of files with these "standard" * one-index files */ /* Check files with multiple indexes. */ /* These files should be larger when first created than one-index * files. */ if (mult_index_med.empty_size <= list_index_med.empty_size) VERIFY(0, 1, "h5_get_file_size"); if (mult_index_btree.empty_size != mult_index_med.empty_size) VERIFY(0, 1, "h5_get_file_size"); /* When the first dataset is written, they should grow quite a bit as * many different indexes must be created. */ if ((mult_index_med.first_dset - mult_index_med.empty_size) <= (list_index_med.first_dset - list_index_med.empty_size)) VERIFY(0, 1, "h5_get_file_size"); if ((mult_index_btree.first_dset - mult_index_btree.empty_size) <= (btree_index.first_dset - btree_index.empty_size)) VERIFY(0, 1, "h5_get_file_size"); /* When the second dataset is written, they should grow less as * some extra heap space is allocated, but no more indices. */ if ((mult_index_med.second_dset - mult_index_med.first_dset) > (mult_index_med.first_dset - mult_index_med.empty_size)) VERIFY(0, 1, "h5_get_file_size"); if ((list_index_med.second_dset - list_index_med.first_dset) > (list_index_med.first_dset - list_index_med.empty_size)) VERIFY(0, 1, "h5_get_file_size"); if ((mult_index_btree.second_dset - mult_index_btree.first_dset) > (mult_index_btree.first_dset - mult_index_btree.empty_size)) VERIFY(0, 1, "h5_get_file_size"); if ((btree_index.second_dset - btree_index.first_dset) > (btree_index.first_dset - btree_index.empty_size)) VERIFY(0, 1, "h5_get_file_size"); /* And the size delta for the second dataset is less in files with only * one index. */ if ((mult_index_med.second_dset - mult_index_med.first_dset) <= (list_index_med.second_dset - list_index_med.first_dset)) VERIFY(0, 1, "h5_get_file_size"); if ((mult_index_btree.first_dset - mult_index_btree.empty_size) <= (btree_index.first_dset - btree_index.empty_size)) VERIFY(0, 1, "h5_get_file_size"); /* Once that initial overhead is out of the way and the lists/btrees * have been created, files with more than one index should grow at * the same rate or slightly faster than files with just one index * and one heap. */ if ((mult_index_med.dsets1 - mult_index_med.second_dset) != (list_index_med.dsets1 - list_index_med.second_dset)) VERIFY((mult_index_med.dsets1 - mult_index_med.second_dset), (list_index_med.dsets1 - list_index_med.second_dset), "h5_get_file_size"); if ((mult_index_btree.dsets1 - mult_index_btree.second_dset) != (btree_index.dsets1 - btree_index.second_dset)) VERIFY((mult_index_btree.dsets1 - mult_index_btree.second_dset), (btree_index.dsets1 - btree_index.second_dset), "h5_get_file_size"); if ((mult_index_med.dsets2 - mult_index_med.dsets1) > (h5_stat_size_t)((float)(list_index_med.dsets2 - list_index_med.dsets1) * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); if ((mult_index_btree.dsets2 - mult_index_btree.dsets1) > (h5_stat_size_t)((float)(btree_index.dsets2 - btree_index.dsets1) * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); if ((mult_index_med.interleaved - mult_index_med.dsets2) > (h5_stat_size_t)((float)(list_index_med.interleaved - list_index_med.dsets2) * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); if ((mult_index_btree.interleaved - mult_index_btree.dsets2) > (h5_stat_size_t)((float)(btree_index.interleaved - btree_index.dsets2) * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); /* When all the attributes are added, only the index holding attributes * will become a B-tree. Skip the interleaved to attrs1 interval when * this happens because it's hard to predict exactly how much space this * will take. */ if ((mult_index_med.attrs2 - mult_index_med.attrs1) > (h5_stat_size_t)((float)(list_index_med.attrs2 - list_index_med.attrs1) * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); if ((mult_index_btree.attrs2 - mult_index_btree.attrs1) > (h5_stat_size_t)((float)(btree_index.attrs2 - btree_index.attrs1) * OVERHEAD_ALLOWED)) VERIFY(0, 1, "h5_get_file_size"); /* The final file size for both of the multiple index files should be * smaller than a normal file but bigger than any of the one-index files. */ if (mult_index_med.attrs2 >= norm_sizes.attrs2) VERIFY(0, 1, "h5_get_file_size"); if (mult_index_btree.attrs2 >= norm_sizes.attrs2) VERIFY(0, 1, "h5_get_file_size"); if ((h5_stat_size_t)((float)mult_index_med.attrs2 * OVERHEAD_ALLOWED) < btree_index.attrs2) VERIFY(0, 1, "h5_get_file_size"); if ((h5_stat_size_t)((float)mult_index_btree.attrs2 * OVERHEAD_ALLOWED) < btree_index.attrs2) VERIFY(0, 1, "h5_get_file_size"); /* Check files that don't share all messages. */ /* These files have three indexes like the files above, so they should be * the same size when created. */ if (share_some_med.empty_size != mult_index_med.empty_size) VERIFY(0, 1, "h5_get_file_size"); if (share_some_med.empty_size != share_some_btree.empty_size) VERIFY(0, 1, "h5_get_file_size"); /* When the first dataset is created, they should be not quite as big * as equivalent files that share all messages (since shared messages * have a little bit of overhead). */ if (share_some_med.first_dset >= mult_index_med.first_dset) VERIFY(0, 1, "h5_get_file_size"); if (share_some_btree.first_dset >= mult_index_btree.first_dset) VERIFY(0, 1, "h5_get_file_size"); /* The files that share some should have a growth rate in between * files that share all messages and normal files */ if ((share_some_med.interleaved - share_some_med.first_dset) <= (mult_index_med.interleaved - mult_index_med.first_dset)) VERIFY(0, 1, "h5_get_file_size"); if ((share_some_med.interleaved - share_some_med.first_dset) >= (norm_sizes.interleaved - norm_sizes.first_dset)) VERIFY(0, 1, "h5_get_file_size"); if ((share_some_btree.interleaved - share_some_btree.first_dset) <= (mult_index_btree.interleaved - mult_index_btree.first_dset)) VERIFY(0, 1, "h5_get_file_size"); if ((share_some_btree.interleaved - share_some_btree.first_dset) >= (norm_sizes.interleaved - norm_sizes.first_dset)) VERIFY(0, 1, "h5_get_file_size"); /* Check the file that only stored gigantic messages in its second * index. Since no messages were that big, it should be identical * to the file with an empty index. */ if (share_some_btree.empty_size != share_some_toobig_index.empty_size) VERIFY(0, 1, "h5_get_file_size"); if (share_some_btree.first_dset != share_some_toobig_index.first_dset) VERIFY(0, 1, "h5_get_file_size"); if (share_some_btree.dsets1 != share_some_toobig_index.dsets1) VERIFY(0, 1, "h5_get_file_size"); if (share_some_btree.dsets2 != share_some_toobig_index.dsets2) VERIFY(0, 1, "h5_get_file_size"); if (share_some_btree.interleaved != share_some_toobig_index.interleaved) VERIFY(0, 1, "h5_get_file_size"); if (share_some_btree.attrs1 != share_some_toobig_index.attrs1) VERIFY(0, 1, "h5_get_file_size"); if (share_some_btree.attrs2 != share_some_toobig_index.attrs2) VERIFY(0, 1, "h5_get_file_size"); /* Check the file that shares even very tiny messages. Once messages * are written to it, it should gain a little space from sharing the * messages and lose a little space to overhead so that it's just slightly * smaller than a file that doesn't share tiny messages. * If the overhead increases or the size of messages decreases, these * numbers may be off. */ if (share_tiny_index.empty_size != type_space_index.empty_size) VERIFY(share_tiny_index.empty_size, type_space_index.empty_size, "h5_get_file_size"); if (share_tiny_index.first_dset >= (h5_stat_size_t)((float)type_space_index.first_dset * OVERHEAD_ALLOWED)) VERIFY(share_tiny_index.first_dset, type_space_index.first_dset, "h5_get_file_size"); if (share_tiny_index.first_dset < type_space_index.first_dset) VERIFY(0, 1, "h5_get_file_size"); if (share_tiny_index.second_dset >= type_space_index.second_dset) VERIFY(share_tiny_index.second_dset, type_space_index.second_dset, "h5_get_file_size"); if ((h5_stat_size_t)((float)share_tiny_index.second_dset * OVERHEAD_ALLOWED) < type_space_index.second_dset) VERIFY(0, 1, "h5_get_file_size"); if (share_tiny_index.dsets1 >= type_space_index.dsets1) VERIFY(0, 1, "h5_get_file_size"); if ((h5_stat_size_t)((float)share_tiny_index.dsets1 * OVERHEAD_ALLOWED) < type_space_index.dsets1) VERIFY(0, 1, "h5_get_file_size"); if (share_tiny_index.dsets2 >= type_space_index.dsets2) VERIFY(0, 1, "h5_get_file_size"); if ((h5_stat_size_t)((float)share_tiny_index.dsets2 * OVERHEAD_ALLOWED) < type_space_index.dsets2) VERIFY(0, 1, "h5_get_file_size"); if (share_tiny_index.interleaved >= type_space_index.interleaved) VERIFY(0, 1, "h5_get_file_size"); if ((h5_stat_size_t)((float)share_tiny_index.interleaved * OVERHEAD_ALLOWED) < type_space_index.interleaved) VERIFY(0, 1, "h5_get_file_size"); if (share_tiny_index.attrs1 >= type_space_index.attrs1) VERIFY(0, 1, "h5_get_file_size"); if ((h5_stat_size_t)((float)share_tiny_index.attrs1 * OVERHEAD_ALLOWED) < type_space_index.attrs1) VERIFY(0, 1, "h5_get_file_size"); if (share_tiny_index.attrs2 >= type_space_index.attrs2) VERIFY(0, 1, "h5_get_file_size"); if ((h5_stat_size_t)((float)share_tiny_index.attrs2 * OVERHEAD_ALLOWED) < type_space_index.attrs2) VERIFY(0, 1, "h5_get_file_size"); } /* test_sohm_size2 */ /*------------------------------------------------------------------------- * Function: delete_helper_write * * Purpose: Creates a dataset and attribute in file FILE_ID using value X * in the DSPACE_ID and DCPL_ID arrays. * *------------------------------------------------------------------------- */ static void delete_helper_write(hid_t file_id, hid_t *dspace_id, hid_t *dcpl_id, int x) { hid_t dset_id = H5I_INVALID_HID; hid_t attr_id = H5I_INVALID_HID; char wdata; herr_t ret; dset_id = H5Dcreate2(file_id, DSETNAME[x], H5T_NATIVE_CHAR, dspace_id[x], H5P_DEFAULT, dcpl_id[x], H5P_DEFAULT); CHECK_I(dset_id, "H5Dcreate2"); wdata = (char)(x + 'a'); ret = H5Dwrite(dset_id, H5T_NATIVE_CHAR, dspace_id[x], dspace_id[x], H5P_DEFAULT, &wdata); CHECK_I(ret, "H5Dwrite"); attr_id = H5Acreate2(dset_id, "attr_name", H5T_NATIVE_CHAR, dspace_id[x], H5P_DEFAULT, H5P_DEFAULT); CHECK_I(attr_id, "H5Acreate2"); ret = H5Awrite(attr_id, H5T_NATIVE_CHAR, &wdata); CHECK_I(ret, "H5Awrite"); ret = H5Aclose(attr_id); CHECK_I(ret, "H5Aclose"); ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); } /* delete_helper_write */ /*------------------------------------------------------------------------- * Function: delete_helper_read * * Purpose: Checks the value of the dataset and attribute created by * delete_helper_write. * *------------------------------------------------------------------------- */ static void delete_helper_read(hid_t file_id, hid_t *dspace_id, int x) { hid_t dset_id = H5I_INVALID_HID; hid_t attr_id = H5I_INVALID_HID; char rdata; herr_t ret; dset_id = H5Dopen2(file_id, DSETNAME[x], H5P_DEFAULT); CHECK_I(dset_id, "H5Dopen2"); rdata = '\0'; ret = H5Dread(dset_id, H5T_NATIVE_CHAR, dspace_id[x], dspace_id[x], H5P_DEFAULT, &rdata); CHECK_I(ret, "H5Dread"); VERIFY(rdata, (x + 'a'), "H5Dread"); attr_id = H5Aopen(dset_id, "attr_name", H5P_DEFAULT); CHECK_I(attr_id, "H5Aopen"); rdata = '\0'; ret = H5Aread(attr_id, H5T_NATIVE_CHAR, &rdata); CHECK_I(ret, "H5Dread"); VERIFY(rdata, (x + 'a'), "H5Dread"); ret = H5Aclose(attr_id); CHECK_I(ret, "H5Aclose"); ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); } /* delete_helper_read */ /*------------------------------------------------------------------------- * Function: delete_helper * * Purpose: Creates some shared messages, deletes them, and creates some * more messages. The second batch of messages should use the * space freed by the first batch, so should be about the same * size as a file that never had the first batch of messages * created. * * FCPL_ID is the file creation property list to use. * DSPACE_ID and DCPL_ID are arrays of different dataspaces * and property lists with filter pipelines used to create the * messages. * *------------------------------------------------------------------------- */ static void delete_helper(hid_t fcpl_id, hid_t *dspace_id, hid_t *dcpl_id) { hid_t file_id = H5I_INVALID_HID; int x; h5_stat_size_t norm_filesize; h5_stat_size_t deleted_filesize; herr_t ret; /* Get the size of a "normal" file with no deleted messages */ file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); CHECK_I(file_id, "H5Fcreate"); /* Create batch of messages in the file starting at message 2 */ for (x = HALF_DELETE_NUM_MESGS; x < DELETE_NUM_MESGS; ++x) { delete_helper_write(file_id, dspace_id, dcpl_id, x); } /* Check that messages can be read */ for (x = HALF_DELETE_NUM_MESGS; x < DELETE_NUM_MESGS; ++x) { delete_helper_read(file_id, dspace_id, x); } /* Close file and get filesize */ ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); norm_filesize = h5_get_file_size(FILENAME, H5P_DEFAULT); /* Create a new file with messages 0 to (HALF_DELETE_NUM_MESGS - 1) */ file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); CHECK_I(file_id, "H5Fcreate"); for (x = 0; x < HALF_DELETE_NUM_MESGS; ++x) { delete_helper_write(file_id, dspace_id, dcpl_id, x); } /* Verify each dataset, then delete it (which should delete * its shared messages as well */ for (x = 0; x < HALF_DELETE_NUM_MESGS; ++x) { delete_helper_read(file_id, dspace_id, x); ret = H5Ldelete(file_id, DSETNAME[x], H5P_DEFAULT); CHECK_I(ret, "H5Ldelete"); } /* The file is now empty. Write and verify the second batch of messages * again. */ for (x = HALF_DELETE_NUM_MESGS; x < DELETE_NUM_MESGS; ++x) { delete_helper_write(file_id, dspace_id, dcpl_id, x); } for (x = HALF_DELETE_NUM_MESGS; x < DELETE_NUM_MESGS; ++x) { delete_helper_read(file_id, dspace_id, x); } /* Close file and get filesize */ ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); deleted_filesize = h5_get_file_size(FILENAME, H5P_DEFAULT); /* The two filesizes should be almost the same */ if (norm_filesize > (h5_stat_size_t)((float)deleted_filesize * OVERHEAD_ALLOWED)) VERIFY(norm_filesize, deleted_filesize, "h5_get_file_size"); if (deleted_filesize > (h5_stat_size_t)((float)norm_filesize * OVERHEAD_ALLOWED)) VERIFY(deleted_filesize, norm_filesize, "h5_get_file_size"); } /* delete_helper */ /*------------------------------------------------------------------------- * Function: test_sohm_delete * * Purpose: Tests shared object header message deletion. * * Creates lots of shared messages, then ensures that they * can be deleted without corrupting the remaining messages. * Also checks that indexes convert from B-trees back into * lists. * *------------------------------------------------------------------------- */ static void test_sohm_delete(void) { hid_t fcpl_id; /* We'll use dataspaces and filter pipelines for this test. * Create a number of distinct messages of each type. */ hid_t dspace_id[DELETE_NUM_MESGS] = {0}; hid_t dcpl_id[DELETE_NUM_MESGS] = {0}; unsigned u; int x; hsize_t dims[] = DELETE_DIMS; herr_t ret; MESSAGE(5, ("Testing deletion of SOHMs\n")); /* Create a number of different dataspaces. * For simplicity, each dataspace has only one element. */ for (u = 0; u < DELETE_NUM_MESGS; ++u) { dspace_id[u] = H5Screate_simple((int)(u + 1), dims, dims); CHECK_I(dspace_id[u], "H5Screate_simple"); } /* end for */ /* Create a number of different filter pipelines. */ dcpl_id[0] = H5Pcreate(H5P_DATASET_CREATE); CHECK_I(dcpl_id[0], "H5Pcreate"); ret = H5Pset_chunk(dcpl_id[0], 1, dims); CHECK_I(ret, "H5Pset_chunk"); ret = H5Pset_shuffle(dcpl_id[0]); CHECK_I(ret, "H5Pset_shuffle"); for (u = 1; u < DELETE_NUM_MESGS; u += 2) { dcpl_id[u] = H5Pcopy(dcpl_id[u - 1]); CHECK_I(dcpl_id[u], "H5Pcopy"); ret = H5Pset_chunk(dcpl_id[u], (int)(u + 1), dims); CHECK_I(ret, "H5Pset_chunk"); ret = H5Pset_deflate(dcpl_id[u], 1); CHECK_I(ret, "H5Pset_deflate"); dcpl_id[u + 1] = H5Pcopy(dcpl_id[u]); CHECK_I(dcpl_id[u + 1], "H5Pcopy"); ret = H5Pset_chunk(dcpl_id[u + 1], (int)(u + 2), dims); CHECK_I(ret, "H5Pset_chunk"); ret = H5Pset_shuffle(dcpl_id[u + 1]); CHECK_I(ret, "H5Pset_shuffle"); } /* end for */ /* Create an fcpl where all messages are shared in the same index */ fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl_id, 1); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_ALL_FLAG, 16); CHECK_I(ret, "H5Pset_shared_mesg_index"); /* Use big list indexes */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 4 * DELETE_NUM_MESGS, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); /* Test that messages can be created and deleted properly */ delete_helper(fcpl_id, dspace_id, dcpl_id); /* Use B-tree indexes */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 0, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); delete_helper(fcpl_id, dspace_id, dcpl_id); /* Use small list indexes that will convert from lists to B-trees and back */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, HALF_DELETE_NUM_MESGS, HALF_DELETE_NUM_MESGS - 1); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); delete_helper(fcpl_id, dspace_id, dcpl_id); /* Use two indexes */ ret = H5Pset_shared_mesg_nindexes(fcpl_id, 2); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_SDSPACE_FLAG | H5O_SHMESG_ATTR_FLAG, 16); CHECK_I(ret, "H5Pset_shared_mesg_index"); ret = H5Pset_shared_mesg_index(fcpl_id, 1, H5O_SHMESG_DTYPE_FLAG, 16); CHECK_I(ret, "H5Pset_shared_mesg_index"); /* Use big list indexes */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 5000, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); /* Use B-tree indexes */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 0, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); delete_helper(fcpl_id, dspace_id, dcpl_id); /* Set phase change values so that one index converts to a B-tree and one doesn't */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, HALF_DELETE_NUM_MESGS + 1, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); delete_helper(fcpl_id, dspace_id, dcpl_id); /* Test with varying message sizes (ideally, so some messages are too * small to be written but some are big enough that they are still written */ ret = H5Pset_shared_mesg_nindexes(fcpl_id, 1); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); for (u = DELETE_MIN_MESG_SIZE; u <= DELETE_MAX_MESG_SIZE; u += 10) { ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_ALL_FLAG, u); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); delete_helper(fcpl_id, dspace_id, dcpl_id); } /* end for */ /* Cleanup */ ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); for (x = DELETE_NUM_MESGS - 1; x >= 0; --x) { ret = H5Sclose(dspace_id[x]); CHECK_I(ret, "H5Sclose"); ret = H5Pclose(dcpl_id[x]); CHECK_I(ret, "H5Pclose"); } /* end for */ } /* test_sohm_delete */ /*------------------------------------------------------------------------- * Function: verify_dset_create_and_delete_does_not_grow_file * * Purpose: Tests that shared object header message deletion returns * the file to its previous state using the supplied FCPL. * * Creates a file according to the supplied FCPL, * then creates datasets and deletes them. * Done in two passes: once with one dataset, once with two. * *------------------------------------------------------------------------- */ static int verify_dset_create_and_delete_does_not_grow_file(hid_t fcpl_id) { hid_t file_id; hid_t dspace_id; hid_t dset_id; hsize_t dims[1] = {1}; h5_stat_size_t initial_filesize, deleted_filesize; int old_nerrs; /* Number of errors when entering this routine */ herr_t ret; /* Retrieve the current # of reported errors */ old_nerrs = GetTestNumErrs(); /* Create a dataspace for later */ dspace_id = H5Screate_simple(1, dims, dims); CHECK_I(dspace_id, "H5Screate_simple"); /* Create a file using the FCPL supplied*/ file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); CHECK_I(file_id, "H5Fcreate"); /* Close the file and get its size */ ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); initial_filesize = h5_get_file_size(FILENAME, H5P_DEFAULT); /* Re-create the file and create a dataset in it */ file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); CHECK_I(file_id, "H5Fcreate"); dset_id = H5Dcreate2(file_id, "dset", H5T_NATIVE_SHORT, dspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(dset_id, "H5Dcreate2"); /* Close the dataset and delete it */ ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); ret = H5Ldelete(file_id, "dset", H5P_DEFAULT); CHECK_I(ret, "H5Ldelete"); /* Close the file and get its size */ ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); deleted_filesize = h5_get_file_size(FILENAME, H5P_DEFAULT); VERIFY(deleted_filesize, initial_filesize, "h5_get_file_size"); /* Repeat, creating two datasets in the file */ file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); CHECK_I(file_id, "H5Fcreate"); /* Create and close the first dataset */ dset_id = H5Dcreate2(file_id, "dset", H5T_NATIVE_SHORT, dspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(dset_id, "H5Dcreate2"); ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); /* Create and close the second. These messages should be shared */ dset_id = H5Dcreate2(file_id, "dset2", H5T_NATIVE_SHORT, dspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(dset_id, "H5Dcreate2"); ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); /* Delete both datasets */ ret = H5Ldelete(file_id, "dset", H5P_DEFAULT); CHECK_I(ret, "H5Ldelete"); ret = H5Ldelete(file_id, "dset2", H5P_DEFAULT); CHECK_I(ret, "H5Ldelete"); /* Close the file and get its size */ ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); deleted_filesize = h5_get_file_size(FILENAME, H5P_DEFAULT); VERIFY(deleted_filesize, initial_filesize, "h5_get_file_size"); /* Cleanup */ ret = H5Sclose(dspace_id); CHECK_I(ret, "H5Sclose"); /* Retrieve current # of errors */ if (old_nerrs == GetTestNumErrs()) return (0); else return (-1); } /* verify_dset_create_and_delete_does_not_grow_file */ /*------------------------------------------------------------------------- * Function: test_sohm_delete_revert * * Purpose: Verifies that creation and deletion of datasets with shared * message headers will not increase file size. * *------------------------------------------------------------------------- */ static void test_sohm_delete_revert(void) { hid_t fcpl_id; herr_t ret; MESSAGE(5, ("Testing that file reverts to original size on SOHM deletion\n")); /* Create an fcpl with messages in two indexes */ fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl_id, 2); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_DTYPE_FLAG, 10); CHECK_I(ret, "H5Pset_shared_mesg_index"); ret = H5Pset_shared_mesg_index(fcpl_id, 1, H5O_SHMESG_SDSPACE_FLAG, 10); CHECK_I(ret, "H5Pset_shared_mesg_index"); /* Call the helper function to test this FCPL. */ ret = verify_dset_create_and_delete_does_not_grow_file(fcpl_id); CHECK_I(ret, "verify_dset_create_and_delete_does_not_grow_file"); /* Try using B-trees */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 0, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); ret = verify_dset_create_and_delete_does_not_grow_file(fcpl_id); CHECK_I(ret, "verify_dset_create_and_delete_does_not_grow_file"); /* Try sharing all messages */ ret = H5Pset_shared_mesg_nindexes(fcpl_id, 1); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_ALL_FLAG, 10); CHECK_I(ret, "H5Pset_shared_mesg_index"); ret = H5Pset_shared_mesg_phase_change(fcpl_id, 10, 5); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); ret = verify_dset_create_and_delete_does_not_grow_file(fcpl_id); CHECK_I(ret, "verify_dset_create_and_delete_does_not_grow_file"); /* Try using B-trees */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 0, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); ret = verify_dset_create_and_delete_does_not_grow_file(fcpl_id); CHECK_I(ret, "verify_dset_create_and_delete_does_not_grow_file"); /* There should be at least two messages in the test (datatype and * dataspace). Use an index that will transition from a list to * a B-tree and back. */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 1, 2); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); ret = verify_dset_create_and_delete_does_not_grow_file(fcpl_id); CHECK_I(ret, "verify_dset_create_and_delete_does_not_grow_file"); /* Try with shared messages enabled, but when messages are too big * to be shared. */ ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_ALL_FLAG, 35); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); ret = verify_dset_create_and_delete_does_not_grow_file(fcpl_id); CHECK_I(ret, "verify_dset_create_and_delete_does_not_grow_file"); ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); } /* test_sohm_delete_revert */ /*------------------------------------------------------------------------- * Function: verify_dset_create_and_open_through_extlink_with_sohm * * Purpose: Tests that a dataset created through an external link can * be opened (that shared messages were created or not and * were shared in the right file). * *------------------------------------------------------------------------- */ static void verify_dset_create_and_open_through_extlink_with_sohm(hid_t src_fcpl_id, hid_t dst_fcpl_id) { hid_t src_file_id = H5I_INVALID_HID; hid_t dst_file_id = H5I_INVALID_HID; hid_t space_id = H5I_INVALID_HID; hid_t dset_id = H5I_INVALID_HID; hsize_t dims[] = {1, 1}; herr_t ret; /* Create files */ src_file_id = H5Fcreate(FILENAME_SRC, H5F_ACC_TRUNC, src_fcpl_id, H5P_DEFAULT); CHECK_I(src_file_id, "H5Fcreate"); dst_file_id = H5Fcreate(FILENAME_DST, H5F_ACC_TRUNC, dst_fcpl_id, H5P_DEFAULT); CHECK_I(dst_file_id, "H5Fcreate"); /* Create an external link from the source file to the destination file */ ret = H5Lcreate_external(FILENAME_DST, "/", src_file_id, "ext_link", H5P_DEFAULT, H5P_DEFAULT); CHECK_I(ret, "H5Lcreate_external"); /* Create a dataset through the external link */ space_id = H5Screate_simple(2, dims, dims); CHECK_I(space_id, "H5Screate_simple"); dset_id = H5Dcreate2(src_file_id, "ext_link/dataset", H5T_NATIVE_FLOAT, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(dset_id, "H5Dcreate2"); /* Close the dataset and both files to make sure everything gets flushed * out of memory */ ret = H5Sclose(space_id); CHECK_I(ret, "H5Sclose"); ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); ret = H5Fclose(src_file_id); CHECK_I(ret, "H5Fclose"); ret = H5Fclose(dst_file_id); CHECK_I(ret, "H5Fclose"); /* Ensure that the dataset can be opened. If the messages were written in * the wrong file, it'll be impossible to read the dataset's object * header. */ dst_file_id = H5Fopen(FILENAME_DST, H5F_ACC_RDONLY, H5P_DEFAULT); CHECK_I(dst_file_id, "H5Fopen"); dset_id = H5Dopen2(dst_file_id, "dataset", H5P_DEFAULT); CHECK_I(dset_id, "H5Dopen2"); /* Cleanup */ ret = H5Dclose(dset_id); CHECK_I(ret, "H5Dclose"); ret = H5Fclose(dst_file_id); CHECK_I(ret, "H5Fclose"); } /* verify_dset_create_and_open_through_extlink_with_sohm */ /*------------------------------------------------------------------------- * Function: test_sohm_extlink * * Purpose: Test creating SOHMs through external links (to make sure that * they're created in the correct file). * *------------------------------------------------------------------------- */ static void test_sohm_extlink(void) { hid_t fcpl_id = H5I_INVALID_HID; bool driver_is_default_compatible; herr_t ret; MESSAGE(5, ("Testing SOHM creation through external links\n")); ret = h5_driver_is_default_vfd_compatible(H5P_DEFAULT, &driver_is_default_compatible); CHECK_I(ret, "h5_driver_is_default_vfd_compatible"); if (!driver_is_default_compatible) { printf("-- SKIPPED --\n"); return; } fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl_id, 1); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_ALL_FLAG, 16); CHECK_I(ret, "H5Pset_shared_mesg_index"); verify_dset_create_and_open_through_extlink_with_sohm(fcpl_id, H5P_DEFAULT); verify_dset_create_and_open_through_extlink_with_sohm(H5P_DEFAULT, fcpl_id); verify_dset_create_and_open_through_extlink_with_sohm(fcpl_id, fcpl_id); ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); } /* test_sohm_extlink */ /*------------------------------------------------------------------------- * Function: verify_dataset_extension * * Purpose: Tests extending a dataset's dataspace when sharing is * enabled. * * If close_reopen is true, closes and reopens the file to * ensure that data is correctly written to disk. * *------------------------------------------------------------------------- */ static int verify_dataset_extension(hid_t fcpl_id, bool close_reopen) { hid_t file_id = H5I_INVALID_HID; hid_t orig_space_id = H5I_INVALID_HID; hid_t space1_id, space2_id, space3_id; hid_t dcpl_id = H5I_INVALID_HID; hid_t dset1_id, dset2_id = H5I_INVALID_HID, dset3_id = H5I_INVALID_HID; hsize_t dims1[] = {1, 2}; hsize_t max_dims[] = {H5S_UNLIMITED, 2}; hsize_t dims2[] = {5, 2}; hsize_t out_dims[2]; hsize_t out_maxdims[2]; int x; int old_nerrs; /* Number of errors when entering this routine */ herr_t ret; hsize_t *space_dims[3]; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Macro: TSOHM_VDE_VERIFY_SPACES * * Purpose: Encapsulate a common pattern * Open, read-verify, and close the dataspaces for datasets 1-3 * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #define TSOHM_VDE_VERIFY_SPACES(dims) \ do { \ /* Open dataspaces \ */ \ space1_id = H5Dget_space(dset1_id); \ CHECK_I(space1_id, "H5Dget_space"); \ space2_id = H5Dget_space(dset2_id); \ CHECK_I(space2_id, "H5Dget_space"); \ space3_id = H5Dget_space(dset3_id); \ CHECK_I(space3_id, "H5Dget_space"); \ /* Verify dataspaces \ */ \ ret = H5Sget_simple_extent_dims(space1_id, out_dims, out_maxdims); \ CHECK_I(ret, "H5Sget_simple_extent_dims"); \ for (x = 0; x < EXTEND_NDIMS; ++x) { \ VERIFY(out_dims[x], (dims)[0][x], "H5Sget_simple_extent_dims"); \ VERIFY(out_maxdims[x], max_dims[x], "H5Sget_simple_extent_dims"); \ } \ ret = H5Sget_simple_extent_dims(space2_id, out_dims, out_maxdims); \ CHECK_I(ret, "H5Sget_simple_extent_dims"); \ for (x = 0; x < EXTEND_NDIMS; ++x) { \ VERIFY(out_dims[x], (dims)[1][x], "H5Sget_simple_extent_dims"); \ VERIFY(out_maxdims[x], max_dims[x], "H5Sget_simple_extent_dims"); \ } \ ret = H5Sget_simple_extent_dims(space3_id, out_dims, out_maxdims); \ CHECK_I(ret, "H5Sget_simple_extent_dims"); \ for (x = 0; x < EXTEND_NDIMS; ++x) { \ VERIFY(out_dims[x], (dims)[2][x], "H5Sget_simple_extent_dims"); \ VERIFY(out_maxdims[x], max_dims[x], "H5Sget_simple_extent_dims"); \ } \ /* Close dataspaces \ */ \ CHECK_I(H5Sclose(space1_id), "H5Sclose"); \ CHECK_I(H5Sclose(space2_id), "H5Sclose"); \ CHECK_I(H5Sclose(space3_id), "H5Sclose"); \ } while (0) /* define TSOHM_VDE_VERIFY_SPACES */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Macro: TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS() * * Purpose: Encapsulate a common pattern * Wrapper to close and reopen file and datasets: * + "dataset" (dset_id) * + if n > 1 then include "dataset2" (dset_id2) * + if n > 2 then include "dataset3" (dset_id3) * + file (file_id) * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #define TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS(n) \ do { \ CHECK_I(H5Dclose(dset1_id), "H5Dclose"); \ if ((n) > 1) \ CHECK_I(H5Dclose(dset2_id), "H5Dclose"); \ if ((n) > 2) \ CHECK_I(H5Dclose(dset3_id), "H5Dclose"); \ CHECK_I(H5Fclose(file_id), "H5Fclose"); \ \ file_id = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); \ CHECK_I(file_id, "H5Fopen"); \ dset1_id = H5Dopen2(file_id, "dataset", H5P_DEFAULT); \ CHECK_I(dset1_id, "H5Dopen2"); \ if ((n) > 1) { \ dset2_id = H5Dopen2(file_id, "dataset2", H5P_DEFAULT); \ CHECK_I(dset2_id, "H5Dopen2"); \ } \ if ((n) > 2) { \ dset3_id = H5Dopen2(file_id, "dataset3", H5P_DEFAULT); \ CHECK_I(dset3_id, "H5Dopen2"); \ } \ } while (0) /* define TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS */ /* Remember the current # of reported errors */ old_nerrs = GetTestNumErrs(); file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); CHECK_I(file_id, "H5Fcreate"); /* Create property list with chunking */ dcpl_id = H5Pcreate(H5P_DATASET_CREATE); CHECK_I(dcpl_id, "H5Pcreate"); ret = H5Pset_chunk(dcpl_id, 2, dims1); CHECK_I(ret, "H5Pset_chunk"); /* Create a dataspace and a dataset*/ orig_space_id = H5Screate_simple(EXTEND_NDIMS, dims1, max_dims); CHECK_I(orig_space_id, "H5Screate_simple"); dset1_id = H5Dcreate2(file_id, "dataset", H5T_NATIVE_LONG, orig_space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); CHECK_I(dset1_id, "H5Dcreate2"); if (close_reopen) TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS(1); /* Create another dataset starting with the same dataspace */ dset2_id = H5Dcreate2(file_id, "dataset2", H5T_NATIVE_LONG, orig_space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); CHECK_I(dset2_id, "H5Dcreate2"); if (close_reopen) TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS(2); /* Create a third dataset with the same dataspace */ dset3_id = H5Dcreate2(file_id, "dataset3", H5T_NATIVE_LONG, orig_space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); CHECK_I(dset3_id, "H5Dcreate2"); if (close_reopen) TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS(3); /* Extend the first dataset */ ret = H5Dset_extent(dset1_id, dims2); CHECK_I(ret, "H5Dset_extent"); if (close_reopen) TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS(3); space_dims[0] = dims2; space_dims[1] = dims1; space_dims[2] = dims1; TSOHM_VDE_VERIFY_SPACES(space_dims); /* Extend the second dataset */ ret = H5Dset_extent(dset2_id, dims2); CHECK_I(ret, "H5Dset_extent"); if (close_reopen) TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS(3); space_dims[1] = dims2; TSOHM_VDE_VERIFY_SPACES(space_dims); /* Extend the third dataset */ ret = H5Dset_extent(dset3_id, dims2); CHECK_I(ret, "H5Dset_extent"); if (close_reopen) TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS(3); space_dims[2] = dims2; TSOHM_VDE_VERIFY_SPACES(space_dims); /* Close the datasets and file */ ret = H5Dclose(dset1_id); CHECK_I(ret, "H5Dclose"); ret = H5Dclose(dset2_id); CHECK_I(ret, "H5Dclose"); ret = H5Dclose(dset3_id); CHECK_I(ret, "H5Dclose"); ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); /* Change the order in which datasets are extended to ensure that there * are no problems if a dataspace goes from being shared to not being * shared or vice versa. */ file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT); CHECK_I(file_id, "H5Fcreate"); dset1_id = H5Dcreate2(file_id, "dataset", H5T_NATIVE_LONG, orig_space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); CHECK_I(dset1_id, "H5Dcreate2"); if (close_reopen) TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS(1); /* Extend the first dataset */ ret = H5Dset_extent(dset1_id, dims2); CHECK_I(ret, "H5Dset_extent"); if (close_reopen) TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS(1); /* Create the second dataset. Its dataspace will be unshared and then * become shared when extended. */ dset2_id = H5Dcreate2(file_id, "dataset2", H5T_NATIVE_LONG, orig_space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); CHECK_I(dset2_id, "H5Dcreate2"); if (close_reopen) TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS(2); /* Extend the second dataset */ ret = H5Dset_extent(dset2_id, dims2); CHECK_I(ret, "H5Dset_extent"); if (close_reopen) TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS(2); /* Create the third dataset. Its dataspace will be unshared and then * become shared when extended. */ dset3_id = H5Dcreate2(file_id, "dataset3", H5T_NATIVE_LONG, orig_space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); CHECK_I(dset3_id, "H5Dcreate2"); if (close_reopen) TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS(3); /* Extend the third dataset */ ret = H5Dset_extent(dset3_id, dims2); CHECK_I(ret, "H5Dset_extent"); if (close_reopen) TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS(3); TSOHM_VDE_VERIFY_SPACES(space_dims); /* Close the datasets and file */ ret = H5Dclose(dset1_id); CHECK_I(ret, "H5Dclose"); ret = H5Dclose(dset2_id); CHECK_I(ret, "H5Dclose"); ret = H5Dclose(dset3_id); CHECK_I(ret, "H5Dclose"); ret = H5Fclose(file_id); CHECK_I(ret, "H5Fclose"); /* Cleanup */ ret = H5Sclose(orig_space_id); CHECK_I(ret, "H5Sclose"); ret = H5Pclose(dcpl_id); CHECK_I(ret, "H5Pclose"); /* Complain if this test generated errors */ if (old_nerrs == GetTestNumErrs()) return (0); else return (-1); /* macros are exclusive to this function */ #undef TSOHM_VDE_CLOSE_REOPEN_FILE_AND_DSETS #undef TSOHM_VDE_VERIFY_SPACES } /* verify_dataset_extension */ /*------------------------------------------------------------------------- * Function: test_sohm_extend_dset * * Purpose: Test extended shared dataspaces. An extended dataset's * dataspace will change, possibly confusing the shared message * code. * *------------------------------------------------------------------------- */ static void test_sohm_extend_dset(void) { hid_t fcpl_id = H5I_INVALID_HID; herr_t ret; MESSAGE(5, ("Testing extending shared dataspaces\n")); fcpl_id = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl_id, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl_id, 1); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); /* No shared messages */ ret = verify_dataset_extension(fcpl_id, false); CHECK_I(ret, "verify_dataset_extension"); ret = verify_dataset_extension(fcpl_id, true); CHECK_I(ret, "verify_dataset_extension"); /* Only dataspaces */ ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_SDSPACE_FLAG, 16); CHECK_I(ret, "H5Pset_shared_mesg_index"); ret = verify_dataset_extension(fcpl_id, false); CHECK_I(ret, "verify_dataset_extension"); ret = verify_dataset_extension(fcpl_id, true); CHECK_I(ret, "verify_dataset_extension"); /* All messages */ ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_ALL_FLAG, 16); CHECK_I(ret, "H5Pset_shared_mesg_index"); ret = verify_dataset_extension(fcpl_id, false); CHECK_I(ret, "verify_dataset_extension"); ret = verify_dataset_extension(fcpl_id, true); CHECK_I(ret, "verify_dataset_extension"); /* All messages in lists */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 100, 50); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); ret = verify_dataset_extension(fcpl_id, false); CHECK_I(ret, "verify_dataset_extension"); ret = verify_dataset_extension(fcpl_id, true); CHECK_I(ret, "verify_dataset_extension"); /* All messages in lists converted to B-trees */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 1, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); ret = verify_dataset_extension(fcpl_id, false); CHECK_I(ret, "verify_dataset_extension"); ret = verify_dataset_extension(fcpl_id, true); CHECK_I(ret, "verify_dataset_extension"); /* All messages in B-trees */ ret = H5Pset_shared_mesg_phase_change(fcpl_id, 0, 0); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); ret = verify_dataset_extension(fcpl_id, false); CHECK_I(ret, "verify_dataset_extension"); ret = verify_dataset_extension(fcpl_id, true); CHECK_I(ret, "verify_dataset_extension"); ret = H5Pclose(fcpl_id); CHECK_I(ret, "H5Pclose"); } /* test_sohm_extend_dset */ /*------------------------------------------------------------------------- * Function: test_sohm_external_dtype * * Purpose: When a datatype is a SOHM type in one file, test that the * second file using the same datatype actually save it in * the file, too. * *------------------------------------------------------------------------- */ static void test_sohm_external_dtype(void) { typedef struct s1_t { int a; int b; } s1_t; s1_t *s_ptr, *orig; hid_t fcpl, file1, file2; hid_t dataset1, dataset2; hid_t s1_tid, dset1_tid, dset2_tid, space; hsize_t dims[2] = {NX, NY}; H5T_class_t dtype_class; size_t dmsg_count; unsigned x, i; herr_t ret; MESSAGE(5, ("Testing shared external datatype\n")); fcpl = H5Pcreate(H5P_FILE_CREATE); CHECK_I(fcpl, "H5Pcreate"); ret = H5Pset_shared_mesg_nindexes(fcpl, TEST_NUM_INDEXES); CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); for (x = 0; x < TEST_NUM_INDEXES; ++x) { ret = H5Pset_shared_mesg_index(fcpl, x, test_type_flags[x], test_minsizes[x]); CHECK_I(ret, "H5Pset_shared_mesg_index"); } ret = H5Pset_shared_mesg_phase_change(fcpl, TEST_L2B, TEST_B2L); CHECK_I(ret, "H5Pset_shared_mesg_phase_change"); space = H5Screate_simple(2, dims, NULL); CHECK_I(space, "H5Screate_simple"); s1_tid = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); CHECK_I(s1_tid, "H5Tcreate"); ret = H5Tinsert(s1_tid, "a", HOFFSET(s1_t, a), H5T_NATIVE_INT); CHECK_I(ret, "H5Tinsert"); ret = H5Tinsert(s1_tid, "b", HOFFSET(s1_t, b), H5T_NATIVE_INT); CHECK_I(ret, "H5Tinsert"); /* Set up dataset in first file */ file1 = H5Fcreate(FILENAME_SRC, H5F_ACC_TRUNC, fcpl, H5P_DEFAULT); CHECK_I(file1, "H5Fcreate"); /* Check on datatype storage status. It should be zero now. */ ret = H5F__get_sohm_mesg_count_test(file1, H5O_DTYPE_ID, &dmsg_count); CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); VERIFY(dmsg_count, 0, "H5F__get_sohm_mesg_count_test"); dataset1 = H5Dcreate2(file1, "dataset_1", s1_tid, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(dataset1, "H5Dcreate2"); /* Check on datatype storage status. It should be 1 now. */ ret = H5F__get_sohm_mesg_count_test(file1, H5O_DTYPE_ID, &dmsg_count); CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); VERIFY(dmsg_count, 1, "H5F__get_sohm_mesg_count_test"); dset1_tid = H5Dget_type(dataset1); CHECK_I(dset1_tid, "H5Dget_type"); /* Allocate space and initialize data */ orig = (s1_t *)malloc(NX * NY * sizeof(s1_t)); if (orig == NULL) CHECK_I(-1, "malloc"); for (i = 0; i < NX * NY; i++) { s_ptr = (s1_t *)orig + i; s_ptr->a = (int)(i * 3 + 1); s_ptr->b = (int)(i * 3 + 2); } ret = H5Dwrite(dataset1, s1_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, orig); CHECK_I(ret, "H5Dwrite"); ret = H5Dclose(dataset1); CHECK_I(ret, "H5Dclose"); /* Create dataset in second file using datatype from dataset in the first file */ file2 = H5Fcreate(FILENAME_DST, H5F_ACC_TRUNC, fcpl, H5P_DEFAULT); CHECK_I(file2, "H5Fcreate"); /* Check on datatype storage status. It should be zero now. */ ret = H5F__get_sohm_mesg_count_test(file2, H5O_DTYPE_ID, &dmsg_count); CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); VERIFY(dmsg_count, 0, "H5F__get_sohm_mesg_count_test"); dataset2 = H5Dcreate2(file2, "dataset_2", dset1_tid, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); CHECK_I(dataset2, "H5Dcreate2"); /* Check on datatype storage status. It should be 1 now. */ ret = H5F__get_sohm_mesg_count_test(file2, H5O_DTYPE_ID, &dmsg_count); CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); VERIFY(dmsg_count, 1, "H5F__get_sohm_mesg_count_test"); ret = H5Dwrite(dataset2, s1_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, orig); CHECK_I(ret, "H5Dwrite"); /* Close references to the first file */ ret = H5Dclose(dataset2); CHECK_I(ret, "H5Dclose"); ret = H5Tclose(dset1_tid); CHECK_I(ret, "H5Tclose"); ret = H5Fclose(file1); CHECK_I(ret, "H5Fclose"); /* Verify that datatype details are still accessible by second file */ dataset2 = H5Dopen2(file2, "dataset_2", H5P_DEFAULT); CHECK_I(dataset2, "H5Dopen2"); dset2_tid = H5Dget_type(dataset2); CHECK_I(dset2_tid, "H5Dget_type"); dtype_class = H5Tget_class(dset2_tid); VERIFY(dtype_class, H5T_COMPOUND, "H5Tget_class"); /* Cleanup */ ret = H5Tclose(dset2_tid); CHECK_I(ret, "H5Tclose"); ret = H5Dclose(dataset2); CHECK_I(ret, "H5Dclose"); ret = H5Sclose(space); CHECK_I(ret, "H5Sclose"); ret = H5Tclose(s1_tid); CHECK_I(ret, "H5Tclose"); ret = H5Pclose(fcpl); CHECK_I(ret, "H5Pclose"); ret = H5Fclose(file2); CHECK_I(ret, "H5Fclose"); free(orig); } /* test_sohm_external_dtype */ /**************************************************************** ** ** test_sohm(): Main Shared Object Header Message testing routine. ** ****************************************************************/ void test_sohm(void) { const char *env_h5_drvr; bool vol_is_native; bool default_driver; MESSAGE(5, ("Testing Shared Object Header Messages\n")); /* Check if native VOL is being used */ CHECK(h5_using_native_vol(H5P_DEFAULT, H5I_INVALID_HID, &vol_is_native), FAIL, "h5_using_native_vol"); if (!vol_is_native) { MESSAGE(5, (" -- SKIPPED --\n")); return; } /* Get the VFD to use */ env_h5_drvr = getenv(HDF5_DRIVER); if (env_h5_drvr == NULL) env_h5_drvr = "nomatch"; default_driver = h5_using_default_driver(env_h5_drvr); test_sohm_fcpl(); /* Test SOHMs and file creation plists */ test_sohm_fcpl_errors(); /* Bogus H5P* calls for SOHMs */ /* Only run this test with sec2/default driver */ if (default_driver) test_sohm_size1(); /* Tests the sizes of files with one SOHM */ #if 0 /* TODO: REVEALS BUG TO BE FIXED - SEE JIRA HDFFV-10645 */ test_sohm_size_consistency_open_create(); #endif /* Jira HDFFV-10645 */ test_sohm_attrs(); /* Tests shared messages in attributes */ /* Only run these tests with sec2/default driver */ if (default_driver) { test_sohm_size2(0); /* Tests the sizes of files with multiple SOHMs */ test_sohm_size2(1); /* Tests the sizes of files with multiple * SOHMs, closing and reopening file after * each write. */ } test_sohm_delete(); /* Test deleting shared messages */ test_sohm_delete_revert(); /* Test that a file with SOHMs becomes an * empty file again when they are deleted. */ test_sohm_extlink(); /* Test SOHMs when external links are used */ test_sohm_extend_dset(); /* Test extending shared datasets */ test_sohm_external_dtype(); /* Test using datatype in another file */ } /* test_sohm */ /*------------------------------------------------------------------------- * Function: cleanup_sohm * * Purpose: Cleanup temporary test files * * Return: none * *------------------------------------------------------------------------- */ void cleanup_sohm(void) { HDremove(FILENAME); HDremove(FILENAME_SRC); HDremove(FILENAME_DST); } /* cleanup_sohm */