mirror of
https://github.com/HDFGroup/hdf5.git
synced 2024-12-03 02:32:04 +08:00
7f1e49206d
This is where most people will expect to find license information. The COPYING_LBNL_HDF5 file has also been renamed to LICENSE_LBNL_HDF5. The licenses are unchanged.
4965 lines
158 KiB
C
4965 lines
158 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* 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 LICENSE 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. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/*
|
|
* Onion Virtual File Driver (VFD)
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Verify Onion VFD behavior that is not involved with operations on the
|
|
* backing store.
|
|
*/
|
|
|
|
#include "h5test.h"
|
|
|
|
#include "H5Fprivate.h" /* encode/decode macros */
|
|
#include "H5FDonion.h" /* This file driver's utilities */
|
|
#include "H5FDonion_priv.h" /* Onion file driver internals */
|
|
|
|
/* The Onion VFD uses H5MM calls internally, so any tests that allocate
|
|
* or free memory for said internal structures (e.g., the revision lists)
|
|
* will need to allocate memory using H5MM calls.
|
|
*/
|
|
#include "H5MMprivate.h" /* Memory management */
|
|
|
|
/* 2^n for uint64_t types -- H5_EXP2 unsafe past 32 bits */
|
|
#define U64_EXP2(n) ((uint64_t)1 << (n))
|
|
|
|
#define ONION_TEST_PAGE_SIZE_1 4
|
|
#define ONION_TEST_PAGE_SIZE_5 32
|
|
#define ONION_TEST_FIXNAME_SIZE 1024
|
|
#define ONION_TEST_EXPECTED_HISTORY_REVISIONS_MAX 16
|
|
#define ONION_TEST_REV_REV_WRITES_MAX 8
|
|
#define ONE_DIM_SIZE 1024
|
|
|
|
/* Structure to collect the onion filepaths in one place. */
|
|
struct onion_filepaths {
|
|
char *canon;
|
|
char *onion;
|
|
char *recovery;
|
|
};
|
|
|
|
struct expected_revision {
|
|
uint64_t revision_num;
|
|
uint64_t parent_revision_num;
|
|
uint64_t logical_eof;
|
|
uint64_t n_index_entries;
|
|
const char *comment;
|
|
};
|
|
struct expected_history {
|
|
uint64_t page_size;
|
|
uint64_t n_revisions;
|
|
uint64_t origin_eof;
|
|
struct expected_revision revisions[ONION_TEST_EXPECTED_HISTORY_REVISIONS_MAX];
|
|
};
|
|
|
|
struct write_info {
|
|
haddr_t offset;
|
|
haddr_t size;
|
|
const unsigned char *buf;
|
|
};
|
|
struct revise_revision {
|
|
bool truncate; /* onion-create, truncating any existing data */
|
|
uint64_t revision_num;
|
|
size_t n_writes;
|
|
struct write_info writes[ONION_TEST_REV_REV_WRITES_MAX];
|
|
const char *comment;
|
|
};
|
|
|
|
static int compare_file_bytes_exactly(const char *filepath, hid_t fapl_id, size_t nbytes,
|
|
const unsigned char *exp);
|
|
static int do_onion_open_and_writes(const char *filename, H5FD_onion_fapl_info_t *onion_info_p, size_t n_ops,
|
|
struct revise_revision *about);
|
|
static void onion_filepaths_destroy(struct onion_filepaths *paths);
|
|
static struct onion_filepaths *onion_filepaths_init(const char *basename);
|
|
|
|
/* set at runtime in main() */
|
|
static unsigned int flags_create_s = 0;
|
|
|
|
/* NOTE: b_list must be longer than a_list.
|
|
* Sizes must match respective buffer lengths.
|
|
*/
|
|
|
|
/* twenty-six four-character words beginning with 'a' -> 104 bytes */
|
|
static const unsigned char *a_list_s =
|
|
(const unsigned char *)"abetableacedacesacheacidacneadzeafaragedagesaidsairsajarallyalum"
|
|
"amokantsapesarcsareaartsasksaspsavidaxes";
|
|
uint64_t a_list_size_s = 104;
|
|
|
|
/* fifty-three four-character words beginning with 'b' -> 212 bytes */
|
|
static const unsigned char *b_list_s =
|
|
(const unsigned char *)"badebailbaitbalebanebarebaskbeambeanbearbeenbeerbeltbentbestbide"
|
|
"bikebilebindbirdbiteblipblueboarboatbobsbodyboilboldbollboltbond"
|
|
"boneboobboorboosbootbradbragbratbraybrewbritbrowbuckbudsbunkbunt"
|
|
"buoyburnburybustbuys";
|
|
static uint64_t b_list_size_s = 212;
|
|
|
|
/* Allocate and populate filepaths with h5_fixname'd strings as appropriate.
|
|
* Should be released with onion_filepaths_destroy() when done.
|
|
*/
|
|
static struct onion_filepaths *
|
|
onion_filepaths_init(const char *basename)
|
|
{
|
|
struct onion_filepaths *paths = NULL;
|
|
|
|
if (NULL == (paths = malloc(sizeof(struct onion_filepaths))))
|
|
TEST_ERROR;
|
|
paths->canon = NULL;
|
|
paths->onion = NULL;
|
|
paths->recovery = NULL;
|
|
|
|
if (NULL == (paths->canon = malloc(sizeof(char) * ONION_TEST_FIXNAME_SIZE)))
|
|
TEST_ERROR;
|
|
snprintf(paths->canon, ONION_TEST_FIXNAME_SIZE, "%s", basename);
|
|
|
|
if (NULL == (paths->onion = malloc(sizeof(char) * ONION_TEST_FIXNAME_SIZE)))
|
|
TEST_ERROR;
|
|
snprintf(paths->onion, ONION_TEST_FIXNAME_SIZE, "%s.onion", paths->canon);
|
|
|
|
if (NULL == (paths->recovery = malloc(sizeof(char) * ONION_TEST_FIXNAME_SIZE)))
|
|
TEST_ERROR;
|
|
snprintf(paths->recovery, ONION_TEST_FIXNAME_SIZE, "%s.onion.recovery", paths->canon);
|
|
|
|
return paths;
|
|
|
|
error:
|
|
if (paths != NULL) {
|
|
free(paths->canon);
|
|
free(paths->onion);
|
|
free(paths->recovery);
|
|
}
|
|
free(paths);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Free onion file paths */
|
|
static void
|
|
onion_filepaths_destroy(struct onion_filepaths *paths)
|
|
{
|
|
free(paths->canon);
|
|
free(paths->onion);
|
|
free(paths->recovery);
|
|
free(paths);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* Function: test_archival_index()
|
|
*
|
|
* Purpose: Unit-test mechanisms for the onion archival index.
|
|
* Specifies and verifies index-validation and -search routines.
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_archival_index(void)
|
|
{
|
|
/* We can ignore each entry's physical address and checksum values */
|
|
H5FD_onion_index_entry_t e0 = {1, 474};
|
|
H5FD_onion_index_entry_t e1 = {4, 558};
|
|
H5FD_onion_index_entry_t e2 = {5, 306};
|
|
H5FD_onion_index_entry_t e3 = {9, 515};
|
|
H5FD_onion_index_entry_t e4 = {14, 386};
|
|
H5FD_onion_index_entry_t e5 = {18, 90};
|
|
H5FD_onion_index_entry_t e6 = {19, 94};
|
|
H5FD_onion_index_entry_t e7 = {20, 509};
|
|
H5FD_onion_index_entry_t sorted[8] = {e0, e1, e2, e3, e4, e5, e6, e7};
|
|
H5FD_onion_index_entry_t sorted_duplicates[8] = {e0, e1, e2, e2, e4, e5, e6, e7};
|
|
H5FD_onion_index_entry_t sorted_incomplete[8] = {e1, e3, e4, e5};
|
|
/* Partially-sorted list also aligned to 2 * page-size */
|
|
H5FD_onion_index_entry_t sorted_partial[8] = {e1, e4, e5, e7, e0, e6, e2, e3}; /* 0..3 sorted */
|
|
H5FD_onion_index_entry_t unsorted[8] = {e3, e1, e4, e5, e0, e6, e2, e7};
|
|
H5FD_onion_archival_index_t aix = {
|
|
H5FD_ONION_ARCHIVAL_INDEX_VERSION_CURR, 1, /* page_size_log2 */
|
|
8, /* list must be populated and sorted through 0 .. (count-1) */
|
|
sorted, /* list */
|
|
};
|
|
const H5FD_onion_index_entry_t *entry_out_p = NULL;
|
|
|
|
TESTING("archival index");
|
|
|
|
/*
|
|
* Failing validity checks
|
|
*/
|
|
|
|
/* Invalid version should fail */
|
|
aix.version++;
|
|
if (H5FD__onion_archival_index_is_valid(&aix))
|
|
TEST_ERROR;
|
|
|
|
/* Invalid version should fail */
|
|
aix.version = 0;
|
|
if (H5FD__onion_archival_index_is_valid(&aix))
|
|
TEST_ERROR;
|
|
aix.version = H5FD_ONION_ARCHIVAL_INDEX_VERSION_CURR;
|
|
|
|
/* NULL list should fail */
|
|
aix.list = NULL;
|
|
if (H5FD__onion_archival_index_is_valid(&aix))
|
|
TEST_ERROR;
|
|
|
|
/* List not full should fail */
|
|
aix.list = sorted_incomplete;
|
|
if (H5FD__onion_archival_index_is_valid(&aix))
|
|
TEST_ERROR;
|
|
|
|
/* Unsorted list should fail */
|
|
aix.list = unsorted;
|
|
if (H5FD__onion_archival_index_is_valid(&aix))
|
|
TEST_ERROR;
|
|
|
|
/* List with duplicates should fail */
|
|
aix.list = sorted_duplicates;
|
|
if (H5FD__onion_archival_index_is_valid(&aix))
|
|
TEST_ERROR;
|
|
|
|
/*
|
|
* Passing validity checks
|
|
*/
|
|
|
|
/* Sorted list should pass */
|
|
aix.list = sorted;
|
|
if (!H5FD__onion_archival_index_is_valid(&aix))
|
|
TEST_ERROR;
|
|
|
|
/* Extra elements ignored (should pass) */
|
|
aix.list = sorted_partial;
|
|
aix.n_entries = 4;
|
|
if (!H5FD__onion_archival_index_is_valid(&aix))
|
|
TEST_ERROR;
|
|
|
|
/*
|
|
* Archival index search routine
|
|
*/
|
|
|
|
aix.list = sorted;
|
|
aix.n_entries = 8;
|
|
|
|
/* Check that address not in array returns zero */
|
|
if (H5FD__onion_archival_index_find(&aix, 3, &entry_out_p) != 0)
|
|
TEST_ERROR;
|
|
/* Pointer should remain unset */
|
|
if (entry_out_p != NULL)
|
|
TEST_ERROR;
|
|
|
|
/* Address found should return 1 */
|
|
if (H5FD__onion_archival_index_find(&aix, 4, &entry_out_p) != 1)
|
|
TEST_ERROR;
|
|
/* Pointer should be set */
|
|
if (NULL == entry_out_p)
|
|
TEST_ERROR;
|
|
/* Incorrect address recorded */
|
|
if (558 != entry_out_p->phys_addr)
|
|
TEST_ERROR;
|
|
|
|
/*
|
|
* Test search edge cases
|
|
*/
|
|
|
|
aix.list = sorted_incomplete;
|
|
aix.n_entries = 4;
|
|
|
|
/* Address not in array should return 0 */
|
|
if (H5FD__onion_archival_index_find(&aix, 1, &entry_out_p) != 0)
|
|
TEST_ERROR;
|
|
|
|
/* Address not in array should return 0 */
|
|
if (H5FD__onion_archival_index_find(&aix, 101, &entry_out_p) != 0)
|
|
TEST_ERROR;
|
|
|
|
/*
|
|
* Empty archival index
|
|
*/
|
|
|
|
entry_out_p = NULL;
|
|
aix.n_entries = 0; /* actually populated list is irrelevant */
|
|
/* Address not in array should return 0 */
|
|
if (H5FD__onion_archival_index_find(&aix, 3, &entry_out_p) != 0)
|
|
TEST_ERROR;
|
|
/* Pointer should remain unset */
|
|
if (entry_out_p != NULL)
|
|
TEST_ERROR;
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
return -1;
|
|
} /* end test_archival_index() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* Function: test_revision_index()
|
|
*
|
|
* Purpose: Test revision index functionality
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_revision_index(void)
|
|
{
|
|
H5FD_onion_revision_index_t *rix_p = NULL;
|
|
H5FD_onion_index_entry_t entry = {
|
|
42, /* logical_page */
|
|
111112, /* phys_addr */
|
|
};
|
|
const H5FD_onion_index_entry_t *entry_out_p = NULL;
|
|
|
|
TESTING("revision index");
|
|
|
|
/* Test index creation */
|
|
|
|
if (NULL == (rix_p = H5FD__onion_revision_index_init(ONION_TEST_PAGE_SIZE_5)))
|
|
TEST_ERROR;
|
|
if (H5FD_ONION_REVISION_INDEX_VERSION_CURR != rix_p->version)
|
|
TEST_ERROR;
|
|
if (0 != rix_p->n_entries)
|
|
TEST_ERROR;
|
|
|
|
/* Test missed search */
|
|
|
|
if (H5FD__onion_revision_index_find(rix_p, entry.logical_page, &entry_out_p) != 0)
|
|
TEST_ERROR;
|
|
|
|
/* Test successful insertion and lookup */
|
|
|
|
/* Insertion failed */
|
|
if (H5FD__onion_revision_index_insert(rix_p, &entry) < 0)
|
|
TEST_ERROR;
|
|
if (1 != rix_p->n_entries)
|
|
TEST_ERROR;
|
|
/* Lookup failed */
|
|
if (H5FD__onion_revision_index_find(rix_p, entry.logical_page, &entry_out_p) < 0)
|
|
TEST_ERROR;
|
|
/* Failure to set output parameter */
|
|
if (NULL == entry_out_p)
|
|
TEST_ERROR;
|
|
if (entry.logical_page != entry_out_p->logical_page)
|
|
TEST_ERROR;
|
|
/* Seeking missing page should miss */
|
|
if (H5FD__onion_revision_index_find(rix_p, entry.logical_page + 1, &entry_out_p) != 0)
|
|
TEST_ERROR;
|
|
|
|
/* Test / demonstrate stored entry independent of user object */
|
|
|
|
entry.logical_page = 100;
|
|
entry.phys_addr = 101;
|
|
if (H5FD__onion_revision_index_insert(rix_p, &entry) < 0)
|
|
TEST_ERROR;
|
|
if (2 != rix_p->n_entries)
|
|
TEST_ERROR;
|
|
entry.logical_page = 500;
|
|
entry.phys_addr = 501;
|
|
if (H5FD__onion_revision_index_find(rix_p, 100, &entry_out_p) < 0)
|
|
TEST_ERROR;
|
|
if (100 != entry_out_p->logical_page || 101 != entry_out_p->phys_addr)
|
|
TEST_ERROR;
|
|
|
|
/* Demonstrate updating an entry */
|
|
|
|
/* Error cases */
|
|
|
|
entry.logical_page = 100; /* phys_addr still 501, checksum bbbbbbbb */
|
|
if (H5FD__onion_revision_index_insert(rix_p, &entry) >= 0)
|
|
TEST_ERROR; /* all components but sum must match */
|
|
entry.phys_addr = 101;
|
|
|
|
/* Successful update */
|
|
|
|
entry.logical_page = 100;
|
|
entry.phys_addr = 101;
|
|
if (H5FD__onion_revision_index_insert(rix_p, &entry) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Should still be two unique entries, not three */
|
|
if (2 != rix_p->n_entries)
|
|
TEST_ERROR;
|
|
if (H5FD__onion_revision_index_find(rix_p, 100, &entry_out_p) < 0)
|
|
TEST_ERROR;
|
|
if (100 != entry_out_p->logical_page || 101 != entry_out_p->phys_addr)
|
|
TEST_ERROR;
|
|
|
|
if (H5FD__onion_revision_index_destroy(rix_p) < 0)
|
|
TEST_ERROR;
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
if (rix_p != NULL)
|
|
(void)H5FD__onion_revision_index_destroy(rix_p);
|
|
|
|
return -1;
|
|
} /* end test_revision_index() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* Function: test_revision_index_collisions()
|
|
*
|
|
* Purpose: With knowledge of the revision index implementation, test
|
|
* hash key collisions.
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_revision_index_collisions(void)
|
|
{
|
|
H5FD_onion_revision_index_t *rix_p = NULL;
|
|
H5FD_onion_index_entry_t entry = {
|
|
0, /* logical_page */
|
|
0, /* phys_addr */
|
|
};
|
|
const H5FD_onion_index_entry_t *entry_out_p = NULL;
|
|
const uint64_t n_insert = 40;
|
|
const uint64_t offset_from_power = 5;
|
|
|
|
TESTING("revision index collisions");
|
|
|
|
if (NULL == (rix_p = H5FD__onion_revision_index_init(ONION_TEST_PAGE_SIZE_5)))
|
|
TEST_ERROR;
|
|
|
|
for (uint64_t i = 0; i < n_insert; i++) {
|
|
entry.phys_addr = i;
|
|
entry.logical_page = U64_EXP2(i) + offset_from_power;
|
|
if (H5FD__onion_revision_index_insert(rix_p, &entry) < 0)
|
|
TEST_ERROR;
|
|
}
|
|
|
|
if (n_insert != rix_p->n_entries)
|
|
TEST_ERROR;
|
|
|
|
for (uint64_t i = 0; i < n_insert; i++) {
|
|
uint64_t page_id = U64_EXP2(i) + offset_from_power;
|
|
|
|
if (H5FD__onion_revision_index_find(rix_p, page_id, &entry_out_p) != 1)
|
|
TEST_ERROR;
|
|
if (entry_out_p->phys_addr != i)
|
|
TEST_ERROR;
|
|
}
|
|
|
|
if (H5FD__onion_revision_index_destroy(rix_p) < 0)
|
|
TEST_ERROR;
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
if (rix_p != NULL)
|
|
(void)H5FD__onion_revision_index_destroy(rix_p);
|
|
|
|
return -1;
|
|
} /* end test_revision_index_collisions() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* Function: test_revision_index_resizing()
|
|
*
|
|
* Purpose: With knowledge of the revision index implementation, test
|
|
* one or more resizig of the index.
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_revision_index_resizing(void)
|
|
{
|
|
H5FD_onion_revision_index_t *rix_p = NULL;
|
|
H5FD_onion_index_entry_t entry = {
|
|
0, /* logical_page */
|
|
0, /* phys_addr */
|
|
};
|
|
const H5FD_onion_index_entry_t *entry_out_p = NULL;
|
|
const uint64_t n_insert = U64_EXP2((H5FD_ONION_REVISION_INDEX_STARTING_SIZE_LOG2 + 3));
|
|
|
|
TESTING("revision index resizing");
|
|
|
|
if (NULL == (rix_p = H5FD__onion_revision_index_init(ONION_TEST_PAGE_SIZE_5)))
|
|
TEST_ERROR;
|
|
|
|
for (uint64_t i = 0; i < n_insert; i++) {
|
|
entry.logical_page = i;
|
|
entry.phys_addr = ((uint64_t)(-1) - i);
|
|
if (H5FD__onion_revision_index_insert(rix_p, &entry) < 0)
|
|
TEST_ERROR;
|
|
}
|
|
|
|
if (n_insert != rix_p->n_entries)
|
|
TEST_ERROR;
|
|
|
|
for (uint64_t i = 0; i < n_insert; i++) {
|
|
uint64_t page_id = i;
|
|
|
|
if (H5FD__onion_revision_index_find(rix_p, page_id, &entry_out_p) != 1)
|
|
TEST_ERROR;
|
|
if (entry_out_p->phys_addr != ((uint64_t)(-1) - i))
|
|
TEST_ERROR;
|
|
}
|
|
|
|
if (H5FD__onion_revision_index_destroy(rix_p) < 0)
|
|
TEST_ERROR;
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
if (rix_p != NULL)
|
|
(void)H5FD__onion_revision_index_destroy(rix_p);
|
|
|
|
return -1;
|
|
} /* end test_revision_index_resizing() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* Function: test_revision_index_to_archival_index()
|
|
*
|
|
* Purpose: Verify to_archival_index().
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_revision_index_to_archival_index(void)
|
|
{
|
|
H5FD_onion_revision_index_t *rix_p = NULL;
|
|
H5FD_onion_index_entry_t rix_entry = {
|
|
0, /* logical_page */
|
|
0, /* phys_addr */
|
|
};
|
|
H5FD_onion_archival_index_t aix = {
|
|
H5FD_ONION_ARCHIVAL_INDEX_VERSION_CURR,
|
|
5, /* page_size_log2 */
|
|
0, /* n_entries to be set */
|
|
NULL,
|
|
};
|
|
const uint64_t n_insert = 10;
|
|
|
|
TESTING("revision index to archival index");
|
|
|
|
/*
|
|
* SETUP
|
|
*/
|
|
|
|
if (NULL == (rix_p = H5FD__onion_revision_index_init(ONION_TEST_PAGE_SIZE_5)))
|
|
TEST_ERROR;
|
|
|
|
/* Add scattered entries in reverse order. */
|
|
for (uint64_t i = 0; i < n_insert; i++) {
|
|
uint64_t n = 2003 * (n_insert - i) + 47;
|
|
|
|
rix_entry.logical_page = n;
|
|
rix_entry.phys_addr = n * 13;
|
|
if (H5FD__onion_revision_index_insert(rix_p, &rix_entry) < 0)
|
|
TEST_ERROR;
|
|
}
|
|
|
|
if (n_insert != rix_p->n_entries)
|
|
TEST_ERROR;
|
|
|
|
aix.list = NULL;
|
|
aix.n_entries = 0;
|
|
|
|
/* Successful merge into empty archival index */
|
|
|
|
if (H5FD__onion_merge_revision_index_into_archival_index(rix_p, &aix) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (!H5FD__onion_archival_index_is_valid(&aix))
|
|
TEST_ERROR;
|
|
|
|
if (n_insert != aix.n_entries)
|
|
TEST_ERROR;
|
|
for (uint64_t i = 0; i < n_insert; i++) {
|
|
const H5FD_onion_index_entry_t *aix_entry_p = NULL;
|
|
|
|
uint64_t n = 2003 * (i + 1) + 47;
|
|
|
|
aix_entry_p = &aix.list[i];
|
|
|
|
if (aix_entry_p->logical_page != n)
|
|
TEST_ERROR;
|
|
if (aix_entry_p->phys_addr != (n * 13))
|
|
TEST_ERROR;
|
|
}
|
|
|
|
/* Successful merge into populated archival index */
|
|
|
|
H5MM_xfree(aix.list);
|
|
aix.list = NULL;
|
|
if (NULL == (aix.list = H5MM_malloc(sizeof(H5FD_onion_index_entry_t) * 2)))
|
|
TEST_ERROR;
|
|
aix.list[0].logical_page = 47;
|
|
aix.list[0].phys_addr = 47 * 13;
|
|
aix.list[1].logical_page = (2003 * (n_insert + 1) + 47);
|
|
aix.list[1].phys_addr = (2003 * (n_insert + 1) + 47) * 13;
|
|
aix.n_entries = 2;
|
|
|
|
if (!H5FD__onion_archival_index_is_valid(&aix))
|
|
TEST_ERROR;
|
|
|
|
if (H5FD__onion_merge_revision_index_into_archival_index(rix_p, &aix) < 0)
|
|
TEST_ERROR;
|
|
if (!H5FD__onion_archival_index_is_valid(&aix))
|
|
TEST_ERROR;
|
|
|
|
if (n_insert + 2 != aix.n_entries)
|
|
TEST_ERROR;
|
|
|
|
for (uint64_t i = 0; i < (n_insert + 2); i++) {
|
|
const H5FD_onion_index_entry_t *aix_entry_p = NULL;
|
|
|
|
uint64_t n = 2003 * i + 47;
|
|
|
|
aix_entry_p = &aix.list[i];
|
|
|
|
if (aix_entry_p->logical_page != n)
|
|
TEST_ERROR;
|
|
if (aix_entry_p->phys_addr != (n * 13))
|
|
TEST_ERROR;
|
|
}
|
|
|
|
/* Merged enties from revision index replace existing entries */
|
|
|
|
H5MM_xfree(aix.list);
|
|
aix.list = NULL;
|
|
if (NULL == (aix.list = H5MM_malloc(sizeof(H5FD_onion_index_entry_t) * 2)))
|
|
TEST_ERROR;
|
|
aix.list[0].logical_page = 2003 * (n_insert / 2) + 47;
|
|
aix.list[0].phys_addr = 103;
|
|
aix.list[1].logical_page = 2003 * (n_insert / 2 + 1) + 47;
|
|
aix.list[1].phys_addr = 101;
|
|
aix.n_entries = 2;
|
|
|
|
if (!H5FD__onion_archival_index_is_valid(&aix))
|
|
TEST_ERROR;
|
|
|
|
if (H5FD__onion_merge_revision_index_into_archival_index(rix_p, &aix) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (!H5FD__onion_archival_index_is_valid(&aix))
|
|
TEST_ERROR;
|
|
|
|
if (n_insert != aix.n_entries)
|
|
TEST_ERROR;
|
|
|
|
for (uint64_t i = 0; i < n_insert; i++) {
|
|
const H5FD_onion_index_entry_t *aix_entry_p = NULL;
|
|
uint64_t n = 2003 * (i + 1) + 47;
|
|
|
|
aix_entry_p = &aix.list[i];
|
|
|
|
if (aix_entry_p->logical_page != n)
|
|
TEST_ERROR;
|
|
if (aix_entry_p->phys_addr != (n * 13))
|
|
TEST_ERROR;
|
|
}
|
|
|
|
/* CLEANUP */
|
|
|
|
if (H5FD__onion_revision_index_destroy(rix_p) < 0)
|
|
TEST_ERROR;
|
|
H5MM_xfree(aix.list);
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
if (rix_p)
|
|
(void)H5FD__onion_revision_index_destroy(rix_p);
|
|
H5MM_xfree(aix.list);
|
|
|
|
return -1;
|
|
} /* end test_revision_index_to_archival_index() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* Function: test_fapl()
|
|
*
|
|
* Purpose: Verify H5Pget and set behavior, and data-consistency checks.
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_fapl(void)
|
|
{
|
|
H5FD_onion_fapl_info_t info_in = {
|
|
H5FD_ONION_FAPL_INFO_VERSION_CURR,
|
|
H5P_DEFAULT, /* backing_fapl_id */
|
|
ONION_TEST_PAGE_SIZE_1, /* page_size */
|
|
H5FD_ONION_STORE_TARGET_ONION, /* store_target */
|
|
H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST,
|
|
0, /* force_write_open */
|
|
0, /* creation_flags */
|
|
"indoor speaking voices", /* comment */
|
|
};
|
|
H5FD_onion_fapl_info_t info_out;
|
|
hid_t dxpl_id = H5I_INVALID_HID;
|
|
hid_t fapl_id = H5I_INVALID_HID;
|
|
hid_t fapl_id_sec2 = H5I_INVALID_HID;
|
|
herr_t ret = FAIL;
|
|
|
|
TESTING("file access property list");
|
|
|
|
if ((dxpl_id = H5Pcreate(H5P_DATASET_XFER)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((fapl_id_sec2 = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_sec2(fapl_id_sec2))
|
|
TEST_ERROR;
|
|
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Set FAPL */
|
|
|
|
/* Invalid fapl should fail */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
ret = H5Pset_fapl_onion(H5I_INVALID_HID, &info_in);
|
|
}
|
|
H5E_END_TRY
|
|
if (SUCCEED == ret)
|
|
TEST_ERROR;
|
|
|
|
/* NULL info pointer should fail */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
ret = H5Pset_fapl_onion(fapl_id, NULL);
|
|
}
|
|
H5E_END_TRY
|
|
if (SUCCEED == ret)
|
|
TEST_ERROR;
|
|
|
|
/* Invalid version should fail */
|
|
info_in.version++;
|
|
H5E_BEGIN_TRY
|
|
{
|
|
ret = H5Pset_fapl_onion(fapl_id, &info_in);
|
|
}
|
|
H5E_END_TRY
|
|
if (SUCCEED == ret)
|
|
TEST_ERROR;
|
|
info_in.version--;
|
|
|
|
/* Page size not a power of 2 should fail */
|
|
info_in.page_size = 7;
|
|
H5E_BEGIN_TRY
|
|
{
|
|
ret = H5Pset_fapl_onion(fapl_id, &info_in);
|
|
}
|
|
H5E_END_TRY
|
|
if (SUCCEED == ret)
|
|
TEST_ERROR;
|
|
|
|
/* Page size <=0 should fail */
|
|
info_in.page_size = 0;
|
|
H5E_BEGIN_TRY
|
|
{
|
|
ret = H5Pset_fapl_onion(fapl_id, &info_in);
|
|
}
|
|
H5E_END_TRY
|
|
if (SUCCEED == ret)
|
|
TEST_ERROR;
|
|
info_in.page_size = ONION_TEST_PAGE_SIZE_1;
|
|
|
|
/* Invalid backing fapl should fail */
|
|
info_in.backing_fapl_id = H5I_INVALID_HID;
|
|
H5E_BEGIN_TRY
|
|
{
|
|
ret = H5Pset_fapl_onion(fapl_id, &info_in);
|
|
}
|
|
H5E_END_TRY
|
|
if (SUCCEED == ret)
|
|
TEST_ERROR;
|
|
|
|
/* Backing fapl not a fapl should fail */
|
|
info_in.backing_fapl_id = dxpl_id;
|
|
H5E_BEGIN_TRY
|
|
{
|
|
ret = H5Pset_fapl_onion(fapl_id, &info_in);
|
|
}
|
|
H5E_END_TRY
|
|
if (SUCCEED == ret)
|
|
TEST_ERROR;
|
|
info_in.backing_fapl_id = H5P_DEFAULT;
|
|
|
|
if (H5Pset_fapl_onion(fapl_id, &info_in) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Get onion fapl info */
|
|
|
|
/* NULL info_out pointer should fail */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
ret = H5Pget_fapl_onion(fapl_id, NULL);
|
|
}
|
|
H5E_END_TRY
|
|
if (SUCCEED == ret)
|
|
TEST_ERROR;
|
|
|
|
/* Invalid fapl should fail */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
ret = H5Pget_fapl_onion(H5I_INVALID_HID, &info_out);
|
|
}
|
|
H5E_END_TRY
|
|
if (SUCCEED == ret)
|
|
TEST_ERROR;
|
|
|
|
/* Non-onion fapl ID should fail */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
ret = H5Pget_fapl_onion(fapl_id_sec2, &info_out);
|
|
}
|
|
H5E_END_TRY
|
|
if (SUCCEED == ret)
|
|
TEST_ERROR;
|
|
|
|
/* Normal case */
|
|
if (H5Pget_fapl_onion(fapl_id, &info_out) < 0)
|
|
TEST_ERROR;
|
|
if (H5FD_ONION_FAPL_INFO_VERSION_CURR != info_out.version)
|
|
TEST_ERROR;
|
|
if (H5P_DEFAULT != info_out.backing_fapl_id)
|
|
TEST_ERROR;
|
|
if (ONION_TEST_PAGE_SIZE_1 != info_out.page_size)
|
|
TEST_ERROR;
|
|
if (H5FD_ONION_STORE_TARGET_ONION != info_out.store_target)
|
|
TEST_ERROR;
|
|
if (H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST != info_out.revision_num)
|
|
TEST_ERROR;
|
|
if (0 != info_out.creation_flags)
|
|
TEST_ERROR;
|
|
if (0 != info_out.force_write_open)
|
|
TEST_ERROR;
|
|
if (strcmp(info_in.comment, info_out.comment))
|
|
TEST_ERROR;
|
|
|
|
/* Cleanup */
|
|
|
|
if (H5Pclose(dxpl_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(fapl_id_sec2) < 0)
|
|
TEST_ERROR;
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Pclose(dxpl_id);
|
|
H5Pclose(fapl_id);
|
|
H5Pclose(fapl_id_sec2);
|
|
}
|
|
H5E_END_TRY
|
|
|
|
return -1;
|
|
} /* end test_fapl() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* Function: test_header_encode_decode()
|
|
*
|
|
* Purpose: Verify onion header encoding and decoding behavior.
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_header_encode_decode(void)
|
|
{
|
|
unsigned char buf[64];
|
|
unsigned char exp[64] = {
|
|
/* bogus but unique values */
|
|
'O', 'H', 'D', 'H', /* NOTE: match signature define in onion_priv.h */
|
|
1, 12, 0, 0, /* NOTE: update version w/ "current" as needed */
|
|
0, 16, 0, 0, 0x11, 0x00, 0, 0, 0x02, 0, 0, 0, /* origin_eof */
|
|
0x40, 0xe2, 0x01, 0, 0, 0, 0, 0, /* history_addr */
|
|
88, 0, 0, 0, 0, 0, 0, 0, /* history_size */
|
|
0, 0, 0, 0 /* sum populated below */
|
|
};
|
|
unsigned char *ptr = NULL;
|
|
uint32_t checksum = 0;
|
|
uint32_t checksum_out = 0;
|
|
size_t i = 0;
|
|
uint64_t size_ret = 0;
|
|
H5FD_onion_header_t hdr;
|
|
H5FD_onion_header_t hdr_out;
|
|
|
|
TESTING("encode/decode history header");
|
|
|
|
checksum = H5_checksum_fletcher32(exp, H5FD_ONION_ENCODED_SIZE_HEADER - 4);
|
|
ptr = exp + H5FD_ONION_ENCODED_SIZE_HEADER - 4;
|
|
UINT32ENCODE(ptr, checksum);
|
|
|
|
hdr.version = H5FD_ONION_HEADER_VERSION_CURR;
|
|
hdr.flags = 12;
|
|
hdr.origin_eof = 8589934609ull;
|
|
hdr.page_size = 4096;
|
|
hdr.history_addr = 123456;
|
|
hdr.history_size = 88;
|
|
|
|
if (H5FD__onion_header_encode(&hdr, buf, &checksum_out) != H5FD_ONION_ENCODED_SIZE_HEADER)
|
|
TEST_ERROR;
|
|
|
|
if (checksum != checksum_out)
|
|
TEST_ERROR;
|
|
|
|
for (i = 0; i < H5FD_ONION_ENCODED_SIZE_HEADER; i++) {
|
|
if (exp[i] != buf[i]) {
|
|
printf("first mismatched byte at %zu: %02x %02x\n", i, exp[i], buf[i]);
|
|
TEST_ERROR;
|
|
}
|
|
}
|
|
|
|
hdr_out.version = H5FD_ONION_HEADER_VERSION_CURR;
|
|
hdr_out.flags = 0;
|
|
hdr_out.page_size = 0;
|
|
hdr_out.history_addr = 0;
|
|
hdr_out.history_size = 0;
|
|
|
|
/* Invalid header signature prevents decoding.
|
|
*/
|
|
|
|
exp[3] = 'X'; /* invalidate encoded signature */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
size_ret = H5FD__onion_header_decode(exp, &hdr_out);
|
|
}
|
|
H5E_END_TRY
|
|
if (0 != size_ret)
|
|
TEST_ERROR;
|
|
|
|
exp[3] = 'H'; /* reset */
|
|
|
|
/* Invalid header version prevents decoding.
|
|
*/
|
|
|
|
exp[4] = 0; /* encoded version 0?!? */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
size_ret = H5FD__onion_header_decode(exp, &hdr_out);
|
|
}
|
|
H5E_END_TRY
|
|
if (0 != size_ret)
|
|
TEST_ERROR;
|
|
|
|
exp[4] = H5FD_ONION_HEADER_VERSION_CURR + 1; /* encoded super-version?! */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
size_ret = H5FD__onion_header_decode(exp, &hdr_out);
|
|
}
|
|
H5E_END_TRY
|
|
if (0 != size_ret)
|
|
TEST_ERROR;
|
|
|
|
/* Reset */
|
|
exp[4] = H5FD_ONION_HEADER_VERSION_CURR;
|
|
|
|
/* Valid header can be decoded */
|
|
|
|
if (H5FD__onion_header_decode(buf, &hdr_out) != H5FD_ONION_ENCODED_SIZE_HEADER)
|
|
TEST_ERROR;
|
|
if (H5FD_ONION_HEADER_VERSION_CURR != hdr_out.version)
|
|
TEST_ERROR;
|
|
if (hdr.flags != hdr_out.flags)
|
|
TEST_ERROR;
|
|
if (hdr.page_size != hdr_out.page_size)
|
|
TEST_ERROR;
|
|
if (hdr.history_addr != hdr_out.history_addr)
|
|
TEST_ERROR;
|
|
if (hdr.history_size != hdr_out.history_size)
|
|
TEST_ERROR;
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
return -1;
|
|
} /* end test_header_encode_decode() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* Function: test_history_encode_decode_empty()
|
|
*
|
|
* Purpose: Verify onion history encoding and decoding behavior.
|
|
* Tests the case of the "empty" history.
|
|
* Verifies behavior in standard error cases.
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_history_encode_decode_empty(void)
|
|
{
|
|
unsigned char buf[32];
|
|
unsigned char exp[32] = {
|
|
'O', 'W', 'H', 'S', /* NOTE: match signature define in onion_priv.h */
|
|
1, 0, 0, 0, /* NOTE: update version w/ "current" as needed */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* sum populated below */
|
|
};
|
|
unsigned char *ptr = NULL;
|
|
uint32_t checksum = 0;
|
|
uint32_t checksum_out = 0;
|
|
size_t i = 0;
|
|
uint64_t size_ret = 0;
|
|
H5FD_onion_history_t history = {
|
|
H5FD_ONION_HISTORY_VERSION_CURR, 0, /* n_revisions */
|
|
NULL, /* list */
|
|
0, /* checksum */
|
|
};
|
|
H5FD_onion_history_t history_out = {
|
|
H5FD_ONION_HISTORY_VERSION_CURR, 0, /* n_revisions */
|
|
NULL, /* list */
|
|
0, /* checksum */
|
|
};
|
|
|
|
TESTING("encode/decode history (empty and failures)");
|
|
|
|
/* Generate checksum but don't store it yet */
|
|
checksum = H5_checksum_fletcher32(exp, H5FD_ONION_ENCODED_SIZE_HISTORY - 4);
|
|
ptr = exp + H5FD_ONION_ENCODED_SIZE_HISTORY - 4;
|
|
UINT32ENCODE(ptr, checksum);
|
|
|
|
if (H5FD__onion_history_encode(&history, buf, &checksum_out) != H5FD_ONION_ENCODED_SIZE_HISTORY)
|
|
TEST_ERROR;
|
|
for (i = 0; i < 20; i++) {
|
|
if (exp[i] != buf[i]) {
|
|
printf("first mismatched byte at %zu: %02x %02x\n", i, exp[i], buf[i]);
|
|
TEST_ERROR;
|
|
}
|
|
}
|
|
if (checksum != checksum_out)
|
|
TEST_ERROR;
|
|
history.checksum = checksum; /* set to compare later */
|
|
|
|
/* Invalid signature prevents decoding */
|
|
|
|
exp[3] = 'X'; /* invalidate encoded signature */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
size_ret = H5FD__onion_history_decode(exp, &history_out);
|
|
}
|
|
H5E_END_TRY
|
|
if (0 != size_ret)
|
|
TEST_ERROR;
|
|
|
|
exp[3] = 'H'; /* reset */
|
|
|
|
/* Invalid version prevents decoding */
|
|
|
|
exp[4] = 0; /* encoded version 0?!? */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
size_ret = H5FD__onion_history_decode(exp, &history_out);
|
|
}
|
|
H5E_END_TRY
|
|
if (0 != size_ret)
|
|
TEST_ERROR;
|
|
|
|
exp[4] = H5FD_ONION_HISTORY_VERSION_CURR + 1;
|
|
H5E_BEGIN_TRY
|
|
{
|
|
size_ret = H5FD__onion_history_decode(exp, &history_out);
|
|
}
|
|
H5E_END_TRY
|
|
if (0 != size_ret)
|
|
TEST_ERROR;
|
|
|
|
exp[4] = H5FD_ONION_HISTORY_VERSION_CURR; /* reset */
|
|
|
|
/* Valid summary can be decoded */
|
|
|
|
if (H5FD__onion_history_decode(buf, &history_out) != H5FD_ONION_ENCODED_SIZE_HISTORY)
|
|
TEST_ERROR;
|
|
if (H5FD_ONION_HISTORY_VERSION_CURR != history_out.version)
|
|
TEST_ERROR;
|
|
if (history.n_revisions != history_out.n_revisions)
|
|
TEST_ERROR;
|
|
if (history.checksum != history_out.checksum)
|
|
TEST_ERROR;
|
|
if (NULL != history_out.record_locs)
|
|
TEST_ERROR;
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
return -1;
|
|
} /* end test_history_encode_decode_empty() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* Function: test_history_encode_decode()
|
|
*
|
|
* Purpose: Verify onion history encoding and decoding behavior.
|
|
* Encode/decode with some set of revision record pointers.
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_history_encode_decode(void)
|
|
{
|
|
unsigned char *buf = NULL;
|
|
unsigned char exp[80] = {
|
|
'O', 'W', 'H', 'S', /* NOTE: match signature define in onion_priv.h */
|
|
1, 0, 0, 0, /* NOTE: update version w/ "current" as needed */
|
|
3, 0, 0, 0, 0, 0, 0, 0,
|
|
/* rev0 pointer */
|
|
56, 2, 0, 0, 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* sum populated below */
|
|
/* rev1 pointer */
|
|
121, 173, 3, 0, 0, 0, 0, 0, 203, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* sum populated below */
|
|
/* rev2 pointer */
|
|
96, 158, 52, 198, 213, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* sum populated below */
|
|
/* final checksum */
|
|
0, 0, 0, 0 /* sum populated below */
|
|
};
|
|
unsigned char *buf_p = NULL;
|
|
uint32_t checksum_out = 0;
|
|
size_t i = 0;
|
|
H5FD_onion_history_t history = {
|
|
H5FD_ONION_HISTORY_VERSION_CURR, 3, /* n_revisions */
|
|
NULL, /* list set below */
|
|
0, /* checksum not set by us */
|
|
};
|
|
H5FD_onion_history_t history_out = {
|
|
H5FD_ONION_HISTORY_VERSION_CURR, 0, /* n_revisions must start as zero */
|
|
NULL, /* list */
|
|
0, /* checksum */
|
|
};
|
|
size_t exp_size =
|
|
H5FD_ONION_ENCODED_SIZE_HISTORY + H5FD_ONION_ENCODED_SIZE_RECORD_POINTER * history.n_revisions;
|
|
|
|
TESTING("encode/decode history");
|
|
|
|
if (80 != exp_size)
|
|
TEST_ERROR;
|
|
|
|
history.record_locs = calloc(history.n_revisions, sizeof(H5FD_onion_record_loc_t));
|
|
if (NULL == history.record_locs)
|
|
TEST_ERROR;
|
|
|
|
/* Must match values in exp */
|
|
history.record_locs[0].phys_addr = 568ull;
|
|
history.record_locs[0].record_size = 238ull;
|
|
history.record_locs[1].phys_addr = 241017ull;
|
|
history.record_locs[1].record_size = 4555ull;
|
|
history.record_locs[2].phys_addr = 918153371232ull;
|
|
history.record_locs[2].record_size = 240ull;
|
|
|
|
/* Populate revision pointer sums in exp */
|
|
for (i = 0; i < history.n_revisions; i++) {
|
|
uint64_t history_pre = H5FD_ONION_ENCODED_SIZE_HISTORY - 4;
|
|
uint64_t ptr_pre = H5FD_ONION_ENCODED_SIZE_RECORD_POINTER - 4;
|
|
uint64_t ptr_size = H5FD_ONION_ENCODED_SIZE_RECORD_POINTER;
|
|
|
|
buf_p = exp + history_pre + ptr_size * i;
|
|
history.record_locs[i].checksum = H5_checksum_fletcher32(buf_p, ptr_pre);
|
|
buf_p += ptr_pre;
|
|
UINT32ENCODE(buf_p, history.record_locs[i].checksum);
|
|
}
|
|
|
|
/* Compute, populate, and store exp final sum */
|
|
history.checksum = H5_checksum_fletcher32(exp, exp_size - 4);
|
|
buf_p = exp + exp_size - 4;
|
|
UINT32ENCODE(buf_p, history.checksum);
|
|
|
|
if (NULL == (buf = malloc(exp_size)))
|
|
TEST_ERROR;
|
|
|
|
if (H5FD__onion_history_encode(&history, buf, &checksum_out) != exp_size)
|
|
TEST_ERROR;
|
|
for (i = 0; i < exp_size; i++) {
|
|
if (exp[i] != buf[i])
|
|
TEST_ERROR;
|
|
}
|
|
if (history.checksum != checksum_out)
|
|
TEST_ERROR;
|
|
|
|
/* Initial decode, gets always-present components */
|
|
|
|
history_out.n_revisions = 0; /* must be initialized to 0 */
|
|
if (H5FD__onion_history_decode(exp, &history_out) != exp_size)
|
|
TEST_ERROR;
|
|
if (H5FD_ONION_HISTORY_VERSION_CURR != history_out.version)
|
|
TEST_ERROR;
|
|
if (history.n_revisions != history_out.n_revisions)
|
|
TEST_ERROR;
|
|
/* Must be created by us */
|
|
if (NULL != history_out.record_locs)
|
|
TEST_ERROR;
|
|
|
|
/* True decode requires allocating space for record pointers */
|
|
|
|
history_out.record_locs = calloc(history_out.n_revisions, sizeof(H5FD_onion_record_loc_t));
|
|
if (NULL == history_out.record_locs)
|
|
TEST_ERROR;
|
|
|
|
if (H5FD__onion_history_decode(exp, &history_out) != exp_size)
|
|
TEST_ERROR;
|
|
if (H5FD_ONION_HISTORY_VERSION_CURR != history_out.version)
|
|
TEST_ERROR;
|
|
if (history.n_revisions != history_out.n_revisions)
|
|
TEST_ERROR;
|
|
if (history.checksum != history_out.checksum)
|
|
TEST_ERROR;
|
|
if (NULL == history_out.record_locs)
|
|
TEST_ERROR;
|
|
for (i = 0; i < history.n_revisions; i++) {
|
|
H5FD_onion_record_loc_t exp_rp = history.record_locs[i];
|
|
H5FD_onion_record_loc_t act_rp = history_out.record_locs[i];
|
|
|
|
if (exp_rp.phys_addr != act_rp.phys_addr)
|
|
TEST_ERROR;
|
|
if (exp_rp.record_size != act_rp.record_size)
|
|
TEST_ERROR;
|
|
if (exp_rp.checksum != act_rp.checksum)
|
|
TEST_ERROR;
|
|
}
|
|
|
|
free(history_out.record_locs);
|
|
free(buf);
|
|
free(history.record_locs);
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
free(history_out.record_locs);
|
|
free(buf);
|
|
free(history.record_locs);
|
|
|
|
return -1;
|
|
} /* end test_history_encode_decode() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* Function: test_revision_record_encode_decode()
|
|
*
|
|
* Purpose: Verify onion revision-record encoding and decoding behavior.
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_revision_record_encode_decode(void)
|
|
{
|
|
/* clang-format off */
|
|
/* Byte array of expected values (FRAGILE!) */
|
|
unsigned char exp[173] = {
|
|
'O', 'R', 'R', 'S', /* Bytes 000-003: signature */
|
|
1, 0, 0, 0, /* Bytes 004-007: version */
|
|
5, 0, 0, 0, 0, 0, 0, 0, /* Bytes 008-015: revision ID */
|
|
2, 0, 0, 0, 0, 0, 0, 0, /* Bytes 016-023: parent revision ID */
|
|
'1', '9', '4', '1', '1', '2', '0', '7', /* Bytes 024-039: time of creation */
|
|
'T', '1', '9', '0', '6', '4', '3', 'Z', /* ... */
|
|
0x11, 0x00, 0, 0, 0x02, 0, 0, 0, /* Bytes 040-047: logical file size */
|
|
0, 16, 0, 0, /* Bytes 048-051: page size */
|
|
4, 0, 0, 0, 0, 0, 0, 0, /* Bytes 052-059: # entries */
|
|
25, 0, 0, 0, /* Bytes 060-063: comment size */
|
|
/* ENTRY 0 */
|
|
0, 0xB0, 0x1E, 0, 0, 0, 0, 0, /* Bytes 064-071: entry 0: logical offset */
|
|
0x4B, 0x02, 0, 0, 0, 0, 0, 0, /* Bytes 072-079: entry 0: physical address */
|
|
0, 0, 0, 0, /* Bytes 080-083: checksum (populated below) */
|
|
/* ENTRY 1 */
|
|
0, 0xF0, 0x2E, 0, 0, 0, 0, 0, /* Bytes 084-091: entry 1: logical offset */
|
|
0xA7, 0, 0, 0, 0, 0, 0, 0, /* Bytes 092-099: entry 1: physical address */
|
|
0, 0, 0, 0, /* Bytes 100-103: checksum (populated below) */
|
|
/* ENTRY 2 */
|
|
0, 0x50, 0x15, 0, 0, 0x20, 0, 0, /* Bytes 104-111: entry 2: logical offset */
|
|
0x11, 0, 0, 0, 0x02, 0, 0, 0, /* Bytes 112-119: entry 2: physical address */
|
|
0, 0, 0, 0, /* Bytes 120-123: checksum (populated below) */
|
|
/* ENTRY 3 */
|
|
0, 0xE0, 0x24, 0, 0, 0, 0, 0, /* Bytes 124-131: entry 3: logical offset */
|
|
0xB1, 0x01, 0, 0, 0, 0, 0, 0, /* Bytes 132-139: entry 3: physical address */
|
|
0, 0, 0, 0, /* Bytes 140-143: checksum (populated below) */
|
|
'E', 'x', 'a', 'm', 'p', 'l', 'e', ' ', /* Bytes 144-168: comment */
|
|
'c', 'o', 'm', 'm', 'e', 'n', 't', ' ', /* ... */
|
|
'm', 'e', 's', 's', 'a', 'g', 'e', '.', /* ... */
|
|
'\0', /* ... */
|
|
0, 0, 0, 0 /* Bytes 169-172: final checksum (populated below) */
|
|
};
|
|
/* clang-format on */
|
|
unsigned char *buf = NULL;
|
|
unsigned char *buf_p = NULL;
|
|
size_t i = 0;
|
|
uint64_t size_ret;
|
|
H5FD_onion_revision_record_t r_out;
|
|
uint32_t checksum = 0;
|
|
bool badness = false;
|
|
char comment[25] = "Example comment message.";
|
|
H5FD_onion_revision_record_t record = {
|
|
H5FD_ONION_REVISION_RECORD_VERSION_CURR,
|
|
5, /* revision ID */
|
|
2, /* parent revision ID */
|
|
{'\0'}, /* time of creation - populated below */
|
|
8589934609ull, /* logical file size */
|
|
{
|
|
H5FD_ONION_ARCHIVAL_INDEX_VERSION_CURR, /* version */
|
|
12, /* page_size_log2 */
|
|
4, /* n_entries */
|
|
NULL, /* list - populated below */
|
|
}, /* archival index struct */
|
|
25, /* comment size */
|
|
comment, /* comment */
|
|
0, /* checksum (computed later) */
|
|
};
|
|
size_t exp_size = H5FD_ONION_ENCODED_SIZE_REVISION_RECORD +
|
|
(H5FD_ONION_ENCODED_SIZE_INDEX_ENTRY * record.archival_index.n_entries) +
|
|
strlen("Example comment message.") + 1;
|
|
|
|
r_out.archival_index.list = NULL;
|
|
r_out.comment = NULL;
|
|
|
|
TESTING("encode/decode revision record");
|
|
|
|
memcpy(record.time_of_creation, "19411207T190643Z", 16);
|
|
record.archival_index.list = calloc(record.archival_index.n_entries, sizeof(H5FD_onion_index_entry_t));
|
|
if (NULL == record.archival_index.list)
|
|
TEST_ERROR;
|
|
|
|
/* Convert logical_page and should match address in expected buffer */
|
|
record.archival_index.list[0].logical_page = 491ull;
|
|
record.archival_index.list[0].phys_addr = 587ull;
|
|
record.archival_index.list[1].logical_page = 751ull;
|
|
record.archival_index.list[1].phys_addr = 167ull;
|
|
record.archival_index.list[2].logical_page = 8589934933ull;
|
|
record.archival_index.list[2].phys_addr = 8589934609ull;
|
|
record.archival_index.list[3].logical_page = 590ull;
|
|
record.archival_index.list[3].phys_addr = 433ull;
|
|
|
|
/* Set expected checksum for each archival index entry in buffer */
|
|
for (i = 0; i < record.archival_index.n_entries; i++) {
|
|
uint64_t rec_pre = H5FD_ONION_ENCODED_SIZE_REVISION_RECORD - 4;
|
|
uint64_t idx_pre = H5FD_ONION_ENCODED_SIZE_INDEX_ENTRY - 4;
|
|
uint64_t idx_size = H5FD_ONION_ENCODED_SIZE_INDEX_ENTRY;
|
|
|
|
buf_p = exp + rec_pre + idx_size * i;
|
|
checksum = H5_checksum_fletcher32(buf_p, idx_pre);
|
|
buf_p += idx_pre;
|
|
UINT32ENCODE(buf_p, checksum);
|
|
}
|
|
|
|
checksum = 0;
|
|
|
|
record.checksum = H5_checksum_fletcher32(exp, exp_size - 4);
|
|
buf_p = exp + exp_size - 4;
|
|
UINT32ENCODE(buf_p, record.checksum);
|
|
|
|
/* Required initialization for record-out structure */
|
|
r_out.version = H5FD_ONION_REVISION_RECORD_VERSION_CURR;
|
|
r_out.comment_size = 0;
|
|
r_out.comment = NULL;
|
|
r_out.archival_index.version = H5FD_ONION_ARCHIVAL_INDEX_VERSION_CURR;
|
|
r_out.archival_index.n_entries = 0;
|
|
r_out.archival_index.list = NULL;
|
|
|
|
if (NULL == (buf = malloc(sizeof(unsigned char) * exp_size)))
|
|
TEST_ERROR;
|
|
|
|
/* Test encode */
|
|
|
|
if (H5FD__onion_revision_record_encode(&record, buf, &checksum) != exp_size)
|
|
TEST_ERROR;
|
|
|
|
for (i = 0; i < exp_size; i++) {
|
|
if (exp[i] != buf[i]) {
|
|
badness = true;
|
|
printf("Bad encoded record - Index %zu: expected 0x%02X but got 0x%02X\n", i,
|
|
(unsigned int)exp[i], (unsigned int)buf[i]);
|
|
}
|
|
}
|
|
if (badness) {
|
|
/* If this fragile test breaks, this information is helpful... */
|
|
printf("INDEX\n");
|
|
for (i = 0; i < exp_size; i++)
|
|
printf("%4zu ", i);
|
|
printf("\n");
|
|
|
|
printf("EXPECTED\n");
|
|
for (i = 0; i < exp_size; i++)
|
|
printf("0x%02X ", (unsigned int)exp[i]);
|
|
printf("\n");
|
|
|
|
printf("ACTUAL\n");
|
|
for (i = 0; i < exp_size; i++)
|
|
printf("0x%02X ", (unsigned int)buf[i]);
|
|
printf("\n");
|
|
}
|
|
if (badness)
|
|
TEST_ERROR;
|
|
if (record.checksum != checksum)
|
|
TEST_ERROR;
|
|
|
|
/* Test decode (malformed encoding) */
|
|
|
|
/* Invalid signature */
|
|
exp[2] = 'Y';
|
|
H5E_BEGIN_TRY
|
|
{
|
|
size_ret = H5FD__onion_revision_record_decode(exp, &r_out);
|
|
}
|
|
H5E_END_TRY
|
|
if (0 != size_ret)
|
|
TEST_ERROR;
|
|
exp[2] = 'R'; /* reset */
|
|
|
|
/* Zero version */
|
|
exp[4] = 0;
|
|
H5E_BEGIN_TRY
|
|
{
|
|
size_ret = H5FD__onion_revision_record_decode(exp, &r_out);
|
|
}
|
|
H5E_END_TRY
|
|
if (0 != size_ret)
|
|
TEST_ERROR;
|
|
|
|
/* Advance version */
|
|
exp[4] = H5FD_ONION_REVISION_RECORD_VERSION_CURR + 1;
|
|
H5E_BEGIN_TRY
|
|
{
|
|
size_ret = H5FD__onion_revision_record_decode(exp, &r_out);
|
|
}
|
|
H5E_END_TRY
|
|
if (0 != size_ret)
|
|
TEST_ERROR;
|
|
exp[4] = H5FD_ONION_REVISION_RECORD_VERSION_CURR; /* reset */
|
|
|
|
/* Test successful decode */
|
|
|
|
/* Initial decode; get variable-length component sizes */
|
|
if (H5FD__onion_revision_record_decode(exp, &r_out) != exp_size)
|
|
TEST_ERROR;
|
|
if (record.comment_size != r_out.comment_size)
|
|
TEST_ERROR;
|
|
if (record.archival_index.n_entries != r_out.archival_index.n_entries)
|
|
TEST_ERROR;
|
|
|
|
/* Allocate variable-length components */
|
|
r_out.comment = calloc(r_out.comment_size, sizeof(char));
|
|
if (NULL == r_out.comment)
|
|
TEST_ERROR;
|
|
r_out.archival_index.list = calloc(r_out.archival_index.n_entries, sizeof(H5FD_onion_index_entry_t));
|
|
if (NULL == r_out.archival_index.list)
|
|
TEST_ERROR;
|
|
|
|
/* Decode into all components */
|
|
if (H5FD__onion_revision_record_decode(exp, &r_out) != exp_size)
|
|
TEST_ERROR;
|
|
if (H5FD_ONION_REVISION_RECORD_VERSION_CURR != r_out.version)
|
|
TEST_ERROR;
|
|
if (record.revision_num != r_out.revision_num)
|
|
TEST_ERROR;
|
|
if (record.parent_revision_num != r_out.parent_revision_num)
|
|
TEST_ERROR;
|
|
if (record.parent_revision_num != r_out.parent_revision_num)
|
|
TEST_ERROR;
|
|
if (record.checksum != r_out.checksum)
|
|
TEST_ERROR;
|
|
if (strncmp(record.time_of_creation, r_out.time_of_creation, 16) != 0)
|
|
TEST_ERROR;
|
|
if (record.comment_size != r_out.comment_size)
|
|
TEST_ERROR;
|
|
if (record.comment_size != strlen(r_out.comment) + 1)
|
|
TEST_ERROR;
|
|
if (strlen(record.comment) != strlen(r_out.comment))
|
|
TEST_ERROR;
|
|
if (strcmp(record.comment, r_out.comment) != 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5FD_ONION_ARCHIVAL_INDEX_VERSION_CURR != r_out.archival_index.version)
|
|
TEST_ERROR;
|
|
if (record.archival_index.page_size_log2 != r_out.archival_index.page_size_log2)
|
|
TEST_ERROR;
|
|
if (record.archival_index.n_entries != r_out.archival_index.n_entries)
|
|
TEST_ERROR;
|
|
for (i = 0; i < record.archival_index.n_entries; i++) {
|
|
H5FD_onion_index_entry_t *ep = &record.archival_index.list[i];
|
|
H5FD_onion_index_entry_t *ap = &r_out.archival_index.list[i];
|
|
|
|
if (ep->phys_addr != ap->phys_addr)
|
|
TEST_ERROR;
|
|
if (ep->logical_page != ap->logical_page)
|
|
TEST_ERROR;
|
|
}
|
|
|
|
/* Cleanup */
|
|
|
|
free(r_out.archival_index.list);
|
|
free(r_out.comment);
|
|
free(buf);
|
|
free(record.archival_index.list);
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
free(r_out.archival_index.list);
|
|
free(r_out.comment);
|
|
free(buf);
|
|
free(record.archival_index.list);
|
|
|
|
return -1;
|
|
} /* end test_revision_record_encode_decode() */
|
|
|
|
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
* Use VFL to open target file and check that its bytes exactly match those
|
|
* of given buffer 'exp'[ected].
|
|
*
|
|
* Returns 0 if successful, -1 if error or mismatch.
|
|
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
*/
|
|
static int
|
|
compare_file_bytes_exactly(const char *filepath, hid_t fapl_id, size_t nbytes, const unsigned char *exp)
|
|
{
|
|
H5FD_t *raw_vfile = NULL; /* virtual file to look at raw file contents */
|
|
unsigned char *act_buf = NULL; /* allocated area for actual file bytes */
|
|
uint64_t filesize = 0;
|
|
|
|
if (NULL == (raw_vfile = H5FDopen(filepath, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF)))
|
|
TEST_ERROR;
|
|
|
|
/* filesize is wrong w/ stdio - it's zero instead of 40 or whatnot */
|
|
filesize = (uint64_t)H5FDget_eof(raw_vfile, H5FD_MEM_DRAW);
|
|
if ((uint64_t)nbytes != filesize) {
|
|
fprintf(stderr, "\nSizes not the same - nbytes: %zu, filesize: %" PRIu64 "\n", nbytes, filesize);
|
|
TEST_ERROR;
|
|
}
|
|
|
|
if (NULL == (act_buf = malloc(nbytes)))
|
|
TEST_ERROR;
|
|
/* Fill buffer with bogus UCHAR_MAX values */
|
|
for (size_t i = 0; i < nbytes; i++)
|
|
act_buf[i] = UCHAR_MAX;
|
|
if (H5FDset_eoa(raw_vfile, H5FD_MEM_DRAW, nbytes) < 0)
|
|
TEST_ERROR;
|
|
if (H5FDread(raw_vfile, H5FD_MEM_DRAW, H5P_DEFAULT, 0, nbytes, act_buf) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Compare raw bytes data */
|
|
for (size_t i = 0; i < nbytes; i++) {
|
|
if (exp[i] != act_buf[i]) {
|
|
printf("first mismatched byte %zu: expected 0x%02X was 0x%02X\n", i, exp[i], act_buf[i]);
|
|
TEST_ERROR;
|
|
}
|
|
}
|
|
|
|
if (H5FDclose(raw_vfile) < 0)
|
|
TEST_ERROR;
|
|
free(act_buf);
|
|
|
|
return 0;
|
|
|
|
error:
|
|
if (raw_vfile != NULL)
|
|
H5FDclose(raw_vfile);
|
|
free(act_buf);
|
|
|
|
return -1;
|
|
} /* end compare_file_bytes_exactly() */
|
|
|
|
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
* Do a manual read of the onion history (separate, single "Onion" file).
|
|
* Verify that the history data is well-formed and matches the expected state.
|
|
*
|
|
* Inspect file contents on backing store.
|
|
* Return -1 on problem, 0 if okay.
|
|
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
*/
|
|
static int
|
|
verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filter)
|
|
{
|
|
unsigned char *buf = NULL; /* allocated area for actual file bytes */
|
|
H5FD_onion_header_t hdr_out;
|
|
H5FD_onion_history_t history_out;
|
|
H5FD_onion_revision_record_t rev_out;
|
|
uint64_t filesize = 0;
|
|
uint64_t readsize = 0;
|
|
uint8_t *ui8p = NULL;
|
|
uint32_t buf_checksum = 0;
|
|
|
|
/* memset to avoid bad frees on errors */
|
|
memset(&rev_out, 0, sizeof(H5FD_onion_revision_record_t));
|
|
memset(&history_out, 0, sizeof(H5FD_onion_history_t));
|
|
|
|
hdr_out.version = H5FD_ONION_HEADER_VERSION_CURR;
|
|
|
|
history_out.version = H5FD_ONION_HISTORY_VERSION_CURR;
|
|
history_out.n_revisions = 0;
|
|
history_out.record_locs = NULL;
|
|
|
|
rev_out.version = H5FD_ONION_REVISION_RECORD_VERSION_CURR;
|
|
rev_out.archival_index.version = H5FD_ONION_ARCHIVAL_INDEX_VERSION_CURR;
|
|
|
|
filesize = (uint64_t)H5FDget_eof(raw_file, H5FD_MEM_DRAW);
|
|
if (H5FDset_eoa(raw_file, H5FD_MEM_DRAW, filesize) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Ingest onion header */
|
|
|
|
readsize = MIN(filesize, H5FD_ONION_ENCODED_SIZE_HEADER);
|
|
if (NULL == (buf = malloc(readsize * sizeof(unsigned char))))
|
|
TEST_ERROR;
|
|
if (H5FDread(raw_file, H5FD_MEM_DRAW, H5P_DEFAULT, 0, readsize, buf) < 0)
|
|
TEST_ERROR;
|
|
|
|
readsize = H5FD__onion_header_decode(buf, &hdr_out);
|
|
if (0 == readsize)
|
|
TEST_ERROR;
|
|
if (H5FD_ONION_HEADER_VERSION_CURR != hdr_out.version)
|
|
TEST_ERROR;
|
|
/* Decode from the buffer to we can compare on BE systems */
|
|
ui8p = (uint8_t *)(&buf[readsize - 4]);
|
|
UINT32DECODE(ui8p, buf_checksum);
|
|
if (hdr_out.checksum != buf_checksum)
|
|
TEST_ERROR;
|
|
if (hdr_out.checksum != H5_checksum_fletcher32(buf, readsize - 4))
|
|
TEST_ERROR;
|
|
if (filter->page_size != hdr_out.page_size)
|
|
TEST_ERROR;
|
|
if (hdr_out.history_addr + hdr_out.history_size != filesize)
|
|
TEST_ERROR;
|
|
if (filter->origin_eof != hdr_out.origin_eof)
|
|
TEST_ERROR;
|
|
|
|
free(buf);
|
|
buf = NULL;
|
|
|
|
/* Ingest history */
|
|
|
|
readsize = hdr_out.history_size;
|
|
if (NULL == (buf = malloc(readsize * sizeof(unsigned char))))
|
|
TEST_ERROR;
|
|
if (H5FDread(raw_file, H5FD_MEM_DRAW, H5P_DEFAULT, hdr_out.history_addr, readsize, buf) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Initial read, get count of revisions */
|
|
readsize = H5FD__onion_history_decode(buf, &history_out);
|
|
if (0 == readsize)
|
|
TEST_ERROR;
|
|
if (H5FD_ONION_HISTORY_VERSION_CURR != history_out.version)
|
|
TEST_ERROR;
|
|
/* Decode from the buffer to we can compare on BE systems */
|
|
ui8p = (uint8_t *)(&buf[readsize - 4]);
|
|
UINT32DECODE(ui8p, buf_checksum);
|
|
if (history_out.checksum != buf_checksum)
|
|
TEST_ERROR;
|
|
if (history_out.checksum != H5_checksum_fletcher32(buf, readsize - 4))
|
|
TEST_ERROR;
|
|
if (filter->n_revisions != history_out.n_revisions)
|
|
TEST_ERROR;
|
|
|
|
/* Final read, populate pointers to revision records */
|
|
history_out.record_locs = calloc(history_out.n_revisions, sizeof(H5FD_onion_record_loc_t));
|
|
if (NULL == history_out.record_locs)
|
|
TEST_ERROR;
|
|
if (H5FD__onion_history_decode(buf, &history_out) != readsize)
|
|
TEST_ERROR;
|
|
|
|
/* Reuse buffer space to sanity-check checksum for record pointer(s). */
|
|
assert(readsize >= sizeof(H5FD_onion_record_loc_t));
|
|
for (size_t i = 0; i < history_out.n_revisions; i++) {
|
|
|
|
uint64_t phys_addr;
|
|
uint64_t record_size;
|
|
|
|
/* Do a checked assignment from the struct value into appropriately
|
|
* sized types. We don't have access to the H5F_t struct for this
|
|
* file, so we can't use the offset/length macros in H5Fprivate.h.
|
|
*
|
|
* Have to do an encode to get these values so the test passes on BE
|
|
* systems.
|
|
*/
|
|
H5_CHECKED_ASSIGN(phys_addr, uint64_t, history_out.record_locs[i].phys_addr, haddr_t);
|
|
H5_CHECKED_ASSIGN(record_size, uint64_t, history_out.record_locs[i].record_size, hsize_t);
|
|
|
|
ui8p = (uint8_t *)buf;
|
|
UINT64ENCODE(ui8p, phys_addr);
|
|
|
|
ui8p = (uint8_t *)(buf + 8);
|
|
UINT64ENCODE(ui8p, record_size);
|
|
|
|
if (history_out.record_locs[i].checksum != H5_checksum_fletcher32(buf, 16))
|
|
TEST_ERROR;
|
|
}
|
|
|
|
free(buf);
|
|
buf = NULL;
|
|
|
|
/* Ingest revision(s) */
|
|
|
|
for (size_t i = 0; i < history_out.n_revisions; i++) {
|
|
H5FD_onion_record_loc_t *rpp = &history_out.record_locs[i];
|
|
struct expected_revision *erp = &filter->revisions[i];
|
|
|
|
rev_out.archival_index.list = NULL;
|
|
rev_out.archival_index.n_entries = 0;
|
|
rev_out.archival_index.page_size_log2 = 0;
|
|
rev_out.comment_size = 0;
|
|
rev_out.comment = NULL;
|
|
|
|
readsize = rpp->record_size;
|
|
if (NULL == (buf = malloc((size_t)rpp->record_size)))
|
|
TEST_ERROR;
|
|
if (H5FDread(raw_file, H5FD_MEM_DRAW, H5P_DEFAULT, rpp->phys_addr, rpp->record_size, buf) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Initial revision read -- get fixed components */
|
|
readsize = H5FD__onion_revision_record_decode(buf, &rev_out);
|
|
if (0 == readsize)
|
|
TEST_ERROR;
|
|
if (rpp->record_size != readsize)
|
|
TEST_ERROR;
|
|
if (H5FD_ONION_REVISION_RECORD_VERSION_CURR != rev_out.version)
|
|
TEST_ERROR;
|
|
/* Decode from the buffer to we can compare on BE systems */
|
|
ui8p = (uint8_t *)(&buf[readsize - 4]);
|
|
UINT32DECODE(ui8p, buf_checksum);
|
|
if (rev_out.checksum != buf_checksum)
|
|
TEST_ERROR;
|
|
if (rev_out.checksum != H5_checksum_fletcher32(buf, readsize - 4))
|
|
TEST_ERROR;
|
|
if (erp->revision_num != rev_out.revision_num)
|
|
TEST_ERROR;
|
|
if (erp->parent_revision_num != rev_out.parent_revision_num)
|
|
TEST_ERROR;
|
|
if (erp->logical_eof != rev_out.logical_eof)
|
|
TEST_ERROR;
|
|
|
|
/* Final read, get variable-length data */
|
|
if (NULL == (rev_out.comment = malloc((size_t)rev_out.comment_size)))
|
|
TEST_ERROR;
|
|
rev_out.archival_index.list =
|
|
calloc(rev_out.archival_index.n_entries, sizeof(H5FD_onion_index_entry_t));
|
|
if (NULL == rev_out.archival_index.list)
|
|
TEST_ERROR;
|
|
|
|
readsize = H5FD__onion_revision_record_decode(buf, &rev_out);
|
|
if (rpp->record_size != readsize)
|
|
TEST_ERROR;
|
|
|
|
/* Compare revision info with expected filter */
|
|
if (erp->comment == NULL) {
|
|
if (rev_out.comment_size != 0)
|
|
TEST_ERROR;
|
|
}
|
|
else {
|
|
if (strlen(rev_out.comment) != strlen(erp->comment))
|
|
TEST_ERROR;
|
|
if (strcmp(rev_out.comment, erp->comment) != 0)
|
|
TEST_ERROR;
|
|
}
|
|
if (erp->n_index_entries != (uint64_t)(-1) &&
|
|
erp->n_index_entries != rev_out.archival_index.n_entries)
|
|
TEST_ERROR;
|
|
|
|
free(buf);
|
|
free(rev_out.comment);
|
|
free(rev_out.archival_index.list);
|
|
}
|
|
|
|
free(history_out.record_locs);
|
|
history_out.record_locs = NULL;
|
|
|
|
return 0;
|
|
|
|
error:
|
|
free(buf);
|
|
free(rev_out.comment);
|
|
free(rev_out.archival_index.list);
|
|
free(history_out.record_locs);
|
|
|
|
return -1;
|
|
|
|
} /* end verify_history_as_expected_onion() */
|
|
|
|
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
* Verify file bytes on the backing store
|
|
* + onion storage target
|
|
* + create from nothing
|
|
* + stage 0 (initializing)
|
|
* + open (not yet written)
|
|
* + "Empty" .h5 file created
|
|
* + .onion file created w/ only header (0 whole-hist addr)
|
|
* + .onion.recovery created w/ "empty" history
|
|
* + Cannot open onionized canonical file (incomplete history, no rev)
|
|
*
|
|
* Inspect file contents on backing store.
|
|
* Return -1 on problem, 0 if okay.
|
|
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
*/
|
|
static int
|
|
verify_stored_onion_create_0_open(struct onion_filepaths *paths, H5FD_onion_fapl_info_t *onion_info)
|
|
{
|
|
H5FD_t *file = NULL; /* virtual file to look at raw file contents */
|
|
unsigned char *act_buf = NULL; /* allocated area for actual file bytes */
|
|
hid_t fapl_id = onion_info->backing_fapl_id;
|
|
herr_t err_ret = FAIL;
|
|
unsigned char hdr_exp_bytes[] = {
|
|
'O', 'H', 'D', 'H', 1, 1, 0, 0, 0, 0, 0, 0, /* page-size encoded below */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* checksum encoded below */
|
|
};
|
|
size_t history_exp_bytes_size = 20;
|
|
unsigned char history_exp_bytes[] = {
|
|
'O', 'W', 'H', 'S', 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* checksum encoded below */
|
|
};
|
|
unsigned char *ptr = NULL;
|
|
uint32_t checksum = 0;
|
|
|
|
/* Finish populating expected header bytes */
|
|
ptr = hdr_exp_bytes + 8; /* WARNING: must match format */
|
|
UINT32ENCODE(ptr, onion_info->page_size);
|
|
checksum = H5_checksum_fletcher32(hdr_exp_bytes, H5FD_ONION_ENCODED_SIZE_HEADER - 4);
|
|
ptr = hdr_exp_bytes + H5FD_ONION_ENCODED_SIZE_HEADER - 4;
|
|
UINT32ENCODE(ptr, checksum);
|
|
ptr = NULL;
|
|
|
|
/* Finish populating expected history bytes */
|
|
checksum = H5_checksum_fletcher32(history_exp_bytes, H5FD_ONION_ENCODED_SIZE_HISTORY - 4);
|
|
ptr = history_exp_bytes + H5FD_ONION_ENCODED_SIZE_HISTORY - 4;
|
|
UINT32ENCODE(ptr, checksum);
|
|
ptr = NULL;
|
|
|
|
/* Look at h5 file: should have zero bytes */
|
|
|
|
file = H5FDopen(paths->canon, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF);
|
|
if (NULL == file)
|
|
TEST_ERROR;
|
|
|
|
/* Size here is arbitrary */
|
|
if (NULL == (act_buf = calloc(1, 8)))
|
|
TEST_ERROR;
|
|
|
|
/* Should fail when reading from an empty file */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
err_ret = H5FDread(file, H5FD_MEM_DRAW, H5P_DEFAULT, 0, 1, act_buf);
|
|
}
|
|
H5E_END_TRY
|
|
if (err_ret != FAIL)
|
|
TEST_ERROR;
|
|
|
|
free(act_buf);
|
|
act_buf = NULL;
|
|
|
|
if (H5FDclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = NULL;
|
|
|
|
/* Look at onion file: should have header */
|
|
if (compare_file_bytes_exactly(paths->onion, fapl_id, H5FD_ONION_ENCODED_SIZE_HEADER, hdr_exp_bytes) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Look at history backing file: should have nascent history */
|
|
if (compare_file_bytes_exactly(paths->recovery, fapl_id, history_exp_bytes_size, history_exp_bytes) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Inspect .h5 file contents */
|
|
if (compare_file_bytes_exactly(paths->canon, fapl_id, 8, (const unsigned char *)"ONIONEOF") < 0)
|
|
TEST_ERROR;
|
|
|
|
return 0;
|
|
|
|
error:
|
|
if (file != NULL)
|
|
(void)H5FDclose(file);
|
|
free(act_buf);
|
|
|
|
return -1;
|
|
} /* end verify_stored_onion_create_0_open() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* Function: test_create_oniontarget()
|
|
*
|
|
* Purpose: Test the ability of the Onion VFD to create a valid
|
|
* 'onionized' file.
|
|
*
|
|
* When `truncate_canonical` is false, the canonical file is
|
|
* nonexistent on the backing store on onion-creation.
|
|
* When `truncate_canonical` is true, a canonical file is created
|
|
* on the backing store with known contents, which are to be
|
|
* truncated on onion-creation.
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_create_oniontarget(bool truncate_canonical, bool with_initial_data)
|
|
{
|
|
const char *basename = "somesuch";
|
|
hid_t fapl_id = H5I_INVALID_HID;
|
|
struct onion_filepaths *paths = NULL;
|
|
H5FD_onion_fapl_info_t onion_info = {
|
|
H5FD_ONION_FAPL_INFO_VERSION_CURR,
|
|
H5P_DEFAULT, /* backing_fapl_id */
|
|
ONION_TEST_PAGE_SIZE_5, /* page_size */
|
|
H5FD_ONION_STORE_TARGET_ONION, /* store_target */
|
|
H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST,
|
|
0, /* force_write_open */
|
|
0, /* creation_flags */
|
|
"initial commit" /* comment */
|
|
};
|
|
H5FD_t *vfile_raw = NULL; /* virtual file to look at raw file contents */
|
|
H5FD_t *vfile_rw = NULL; /* Onion virtual file for read/write */
|
|
H5FD_t *vfile_ro = NULL; /* Onion virtual file for read-only */
|
|
struct expected_history filter;
|
|
char *buf = NULL;
|
|
|
|
if (true == truncate_canonical && true == with_initial_data)
|
|
TESTING("onion creation; truncate extant canonical; w/ initial data");
|
|
else if (true == truncate_canonical)
|
|
TESTING("onion creation; truncate extant canonical; no initial data");
|
|
else if (true == with_initial_data)
|
|
TESTING("onion creation; no extant canonical; w/ initial data");
|
|
else
|
|
TESTING("onion creation; no extant canonical; no initial data");
|
|
|
|
/*********
|
|
* SETUP *
|
|
*********/
|
|
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (NULL == (paths = onion_filepaths_init(basename)))
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
|
|
/* Create canonical file to be truncated */
|
|
if (true == truncate_canonical) {
|
|
/* Create canonical file. */
|
|
vfile_raw = H5FDopen(paths->canon, flags_create_s, onion_info.backing_fapl_id, HADDR_UNDEF);
|
|
if (NULL == vfile_raw)
|
|
TEST_ERROR;
|
|
if (H5FDset_eoa(vfile_raw, H5FD_MEM_DRAW, b_list_size_s) < 0)
|
|
TEST_ERROR;
|
|
if (H5FDwrite(vfile_raw, H5FD_MEM_DRAW, H5P_DEFAULT, 0, b_list_size_s, b_list_s) < 0)
|
|
TEST_ERROR;
|
|
if (H5FDclose(vfile_raw) < 0)
|
|
TEST_ERROR;
|
|
|
|
vfile_raw = NULL;
|
|
H5E_BEGIN_TRY
|
|
{
|
|
vfile_raw = H5FDopen(paths->canon, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF);
|
|
}
|
|
H5E_END_TRY
|
|
|
|
/* Check if onion history for onion-open created file */
|
|
if (NULL != vfile_raw)
|
|
TEST_ERROR;
|
|
|
|
/* Create "existing onion file". */
|
|
vfile_raw = H5FDopen(paths->onion, flags_create_s, onion_info.backing_fapl_id, HADDR_UNDEF);
|
|
if (NULL == vfile_raw)
|
|
TEST_ERROR;
|
|
if (H5FDset_eoa(vfile_raw, H5FD_MEM_DRAW, b_list_size_s) < 0)
|
|
TEST_ERROR;
|
|
if (H5FDwrite(vfile_raw, H5FD_MEM_DRAW, H5P_DEFAULT, 0, 23, "prior history stand-in") < 0)
|
|
TEST_ERROR;
|
|
if (H5FDclose(vfile_raw) < 0)
|
|
TEST_ERROR;
|
|
vfile_raw = NULL;
|
|
} /* end if to create canonical file for truncation */
|
|
|
|
/*
|
|
* OPENED
|
|
*/
|
|
|
|
/* Begin creation of onionized file from nothing */
|
|
|
|
vfile_rw = H5FDopen(paths->canon, flags_create_s, fapl_id, HADDR_UNDEF);
|
|
if (NULL == vfile_rw)
|
|
TEST_ERROR;
|
|
|
|
if (verify_stored_onion_create_0_open(paths, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
H5E_BEGIN_TRY
|
|
{
|
|
vfile_ro = H5FDopen(paths->canon, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF);
|
|
}
|
|
H5E_END_TRY
|
|
/* check if onionization (creation) not complete; nothing to open */
|
|
if (vfile_ro != NULL)
|
|
TEST_ERROR;
|
|
|
|
/*
|
|
* WRITING
|
|
*/
|
|
|
|
if (true == with_initial_data) {
|
|
haddr_t half_size = 0;
|
|
haddr_t buf_size = 0;
|
|
|
|
/* Write the sub-page entry at addr 0 */
|
|
if (4 >= onion_info.page_size)
|
|
TEST_ERROR;
|
|
if (H5FDset_eoa(vfile_rw, H5FD_MEM_DRAW, 4) < 0)
|
|
TEST_ERROR;
|
|
if (H5FDwrite(vfile_rw, H5FD_MEM_DRAW, H5P_DEFAULT, 0, 4, a_list_s) < 0) {
|
|
TEST_ERROR;
|
|
}
|
|
|
|
/* Verify logical file contents. */
|
|
if (NULL == (buf = malloc(4 * sizeof(char))))
|
|
TEST_ERROR;
|
|
if (H5FDread(vfile_rw, H5FD_MEM_DRAW, H5P_DEFAULT, 0, 4, buf) < 0)
|
|
TEST_ERROR;
|
|
if (memcmp(a_list_s, buf, 4) != 0)
|
|
TEST_ERROR;
|
|
free(buf);
|
|
buf = NULL;
|
|
|
|
/* Write the latter half of buffer at addr 0 (more than one page) */
|
|
half_size = a_list_size_s / 2;
|
|
buf_size = a_list_size_s - half_size;
|
|
if (buf_size <= onion_info.page_size)
|
|
TEST_ERROR;
|
|
if (H5FDset_eoa(vfile_rw, H5FD_MEM_DRAW, buf_size) < 0)
|
|
TEST_ERROR;
|
|
if (H5FDwrite(vfile_rw, H5FD_MEM_DRAW, H5P_DEFAULT, 0, buf_size, a_list_s + half_size) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Verify logical file contents. */
|
|
if (NULL == (buf = malloc(buf_size * sizeof(char))))
|
|
TEST_ERROR;
|
|
if (H5FDread(vfile_rw, H5FD_MEM_DRAW, H5P_DEFAULT, 0, buf_size, buf) < 0)
|
|
TEST_ERROR;
|
|
if (memcmp(a_list_s + half_size, buf, buf_size) != 0)
|
|
TEST_ERROR;
|
|
free(buf);
|
|
buf = NULL;
|
|
|
|
/* Overwrite existing data with entire buffer at addr 0 */
|
|
if (H5FDset_eoa(vfile_rw, H5FD_MEM_DRAW, a_list_size_s) < 0)
|
|
TEST_ERROR;
|
|
if (H5FDwrite(vfile_rw, H5FD_MEM_DRAW, H5P_DEFAULT, 0, a_list_size_s, a_list_s) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Verify logical file contents. */
|
|
if (NULL == (buf = malloc(a_list_size_s * sizeof(char))))
|
|
TEST_ERROR;
|
|
if (H5FDread(vfile_rw, H5FD_MEM_DRAW, H5P_DEFAULT, 0, a_list_size_s, buf) < 0)
|
|
TEST_ERROR;
|
|
if (memcmp(a_list_s, buf, a_list_size_s) != 0)
|
|
TEST_ERROR;
|
|
free(buf);
|
|
buf = NULL;
|
|
} /* end if writing data to logical file */
|
|
|
|
/*
|
|
* CLOSED
|
|
*/
|
|
|
|
if (H5FDclose(vfile_rw) < 0)
|
|
TEST_ERROR;
|
|
vfile_rw = NULL;
|
|
|
|
/* Look at h5 file: should be known-empty */
|
|
if (compare_file_bytes_exactly(paths->canon, onion_info.backing_fapl_id, 8,
|
|
(const unsigned char *)"ONIONEOF") < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Look at recovery file: should be gone */
|
|
H5E_BEGIN_TRY
|
|
{
|
|
vfile_raw = H5FDopen(paths->recovery, H5F_ACC_RDONLY, onion_info.backing_fapl_id, HADDR_UNDEF);
|
|
}
|
|
H5E_END_TRY
|
|
if (NULL != vfile_raw)
|
|
TEST_ERROR;
|
|
|
|
/* Inspect onion file */
|
|
vfile_raw = H5FDopen(paths->onion, H5F_ACC_RDONLY, onion_info.backing_fapl_id, HADDR_UNDEF);
|
|
if (NULL == vfile_raw)
|
|
TEST_ERROR;
|
|
|
|
filter.page_size = onion_info.page_size;
|
|
filter.n_revisions = 1;
|
|
filter.origin_eof = 0;
|
|
filter.revisions[0].comment = onion_info.comment;
|
|
filter.revisions[0].n_index_entries = (uint64_t)(-1); /* don't care */
|
|
filter.revisions[0].revision_num = 0;
|
|
filter.revisions[0].parent_revision_num = 0;
|
|
filter.revisions[0].logical_eof = (true == with_initial_data) ? a_list_size_s : 0;
|
|
|
|
if (verify_history_as_expected_onion(vfile_raw, &filter) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5FDclose(vfile_raw) < 0)
|
|
TEST_ERROR;
|
|
vfile_raw = NULL;
|
|
|
|
/* R/O open the file with Onion VFD; inspect logical file */
|
|
|
|
vfile_ro = H5FDopen(paths->canon, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF);
|
|
if (NULL == vfile_ro)
|
|
TEST_ERROR;
|
|
|
|
if (true == with_initial_data) {
|
|
/* Initial revision contains data */
|
|
if (H5FDget_eof(vfile_ro, H5FD_MEM_DRAW) != a_list_size_s)
|
|
TEST_ERROR;
|
|
if (H5FDget_eoa(vfile_ro, H5FD_MEM_DRAW) != 0)
|
|
TEST_ERROR;
|
|
if (H5FDset_eoa(vfile_ro, H5FD_MEM_DRAW, a_list_size_s) < 0)
|
|
TEST_ERROR;
|
|
if (NULL == (buf = malloc(a_list_size_s * 64 * sizeof(char))))
|
|
TEST_ERROR;
|
|
if (H5FDread(vfile_ro, H5FD_MEM_DRAW, H5P_DEFAULT, 0, a_list_size_s, buf) < 0)
|
|
TEST_ERROR;
|
|
if (memcmp(a_list_s, buf, a_list_size_s) != 0)
|
|
TEST_ERROR;
|
|
free(buf);
|
|
buf = NULL;
|
|
}
|
|
else {
|
|
/* Initial revision has no data */
|
|
if (H5FDget_eoa(vfile_ro, H5FD_MEM_DRAW) != 0)
|
|
TEST_ERROR;
|
|
if (H5FDget_eof(vfile_ro, H5FD_MEM_DRAW) != 0)
|
|
TEST_ERROR;
|
|
}
|
|
|
|
if (H5FDclose(vfile_ro) < 0)
|
|
TEST_ERROR;
|
|
vfile_ro = NULL;
|
|
|
|
/*
|
|
* CLEANUP
|
|
*/
|
|
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
|
|
if (paths != NULL) {
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
}
|
|
|
|
free(buf);
|
|
|
|
if (vfile_raw != NULL)
|
|
(void)H5FDclose(vfile_raw);
|
|
if (vfile_rw != NULL)
|
|
(void)H5FDclose(vfile_rw);
|
|
if (vfile_ro != NULL)
|
|
(void)H5FDclose(vfile_ro);
|
|
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Pclose(fapl_id);
|
|
}
|
|
H5E_END_TRY
|
|
|
|
return -1;
|
|
} /* end test_create_oniontarget() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* Function: test_several_revisions_with_logical_gaps()
|
|
*
|
|
* Purpose: Test the ability of the Onion VFD to create a valid
|
|
* 'onionized' file.
|
|
*
|
|
* When `truncate_canonical` is false, the canonical file is
|
|
* nonexistent on the backing store on onion-creation.
|
|
* When `truncate_canonical` is true, a canonical file is created
|
|
* on the backing store with known contents, which are to be
|
|
* truncated on onion-creation.
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_several_revisions_with_logical_gaps(void)
|
|
{
|
|
const char *basename = "somesuch";
|
|
hid_t fapl_id = H5I_INVALID_HID;
|
|
struct onion_filepaths *paths = NULL;
|
|
H5FD_onion_fapl_info_t onion_info = {
|
|
H5FD_ONION_FAPL_INFO_VERSION_CURR,
|
|
H5I_INVALID_HID, /* backing_fapl_id */
|
|
ONION_TEST_PAGE_SIZE_5, /* page_size */
|
|
H5FD_ONION_STORE_TARGET_ONION, /* store_target */
|
|
H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST,
|
|
0, /* force_write_open */
|
|
0, /* flags */
|
|
"first" /* comment */
|
|
};
|
|
H5FD_t *file = NULL; /* Onion virtual file for read/write */
|
|
struct expected_history filter;
|
|
unsigned char *buf = NULL;
|
|
struct revise_revision about[4];
|
|
H5FD_onion_history_t history_out;
|
|
size_t i = 0;
|
|
haddr_t size = 0;
|
|
uint64_t a_off = ONION_TEST_PAGE_SIZE_5 + 7; /* 39 */
|
|
uint64_t b_off = (((a_off + a_list_size_s + ONION_TEST_PAGE_SIZE_5 - 1) >> 5) << 5) +
|
|
ONION_TEST_PAGE_SIZE_5 + 7; /* full page between */
|
|
|
|
TESTING("multiple revisions with gaps and overlap");
|
|
|
|
/*********
|
|
* SETUP *
|
|
*********/
|
|
|
|
history_out.version = H5FD_ONION_HISTORY_VERSION_CURR;
|
|
history_out.n_revisions = 0;
|
|
history_out.record_locs = NULL;
|
|
|
|
if (NULL == (paths = onion_filepaths_init(basename)))
|
|
TEST_ERROR;
|
|
|
|
if ((onion_info.backing_fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
|
|
/* Empty first revision */
|
|
about[0].truncate = true;
|
|
about[0].revision_num = H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST;
|
|
about[0].comment = "first";
|
|
about[0].n_writes = 0;
|
|
|
|
about[1].truncate = false;
|
|
about[1].revision_num = H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST;
|
|
about[1].comment = "second";
|
|
about[1].n_writes = 1;
|
|
about[1].writes[0].offset = a_off;
|
|
about[1].writes[0].size = a_list_size_s;
|
|
about[1].writes[0].buf = a_list_s;
|
|
|
|
about[2].truncate = false;
|
|
about[2].revision_num = H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST;
|
|
about[2].comment = "third";
|
|
about[2].n_writes = 1; /* TODO: several writes */
|
|
about[2].writes[0].offset = b_off;
|
|
about[2].writes[0].size = b_list_size_s;
|
|
about[2].writes[0].buf = b_list_s;
|
|
|
|
about[3].truncate = false;
|
|
about[3].revision_num = H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST;
|
|
about[3].comment = "fourth";
|
|
about[3].n_writes = 1;
|
|
about[3].writes[0].offset = 0;
|
|
about[3].writes[0].size = a_list_size_s;
|
|
about[3].writes[0].buf = a_list_s;
|
|
|
|
if (do_onion_open_and_writes(paths->canon, &onion_info, 4, about) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Inspect logical file */
|
|
|
|
/* THIS IS THE INITIAL FILE, SHOULD ONLY HAVE 8 BYTES */
|
|
onion_info.revision_num = 0;
|
|
fapl_id = H5Pcreate(H5P_FILE_ACCESS);
|
|
if (H5I_INVALID_HID == fapl_id)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
file = H5FDopen(paths->canon, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF);
|
|
if (NULL == file)
|
|
TEST_ERROR;
|
|
if (8 != H5FDget_eof(file, H5FD_MEM_DRAW)) {
|
|
printf("\nEOF is not zero, it is: %" PRIuHADDR "\n", H5FDget_eof(file, H5FD_MEM_DRAW));
|
|
TEST_ERROR;
|
|
}
|
|
if (H5FDclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = NULL;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
fapl_id = H5I_INVALID_HID;
|
|
|
|
/* Empty first revision */
|
|
onion_info.revision_num = 1;
|
|
fapl_id = H5Pcreate(H5P_FILE_ACCESS);
|
|
if (H5I_INVALID_HID == fapl_id)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
file = H5FDopen(paths->canon, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF);
|
|
if (NULL == file)
|
|
TEST_ERROR;
|
|
if (0 != H5FDget_eof(file, H5FD_MEM_DRAW)) {
|
|
printf("\nEOF is not zero, it is: %" PRIuHADDR "\n", H5FDget_eof(file, H5FD_MEM_DRAW));
|
|
TEST_ERROR;
|
|
}
|
|
if (H5FDclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = NULL;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
fapl_id = H5I_INVALID_HID;
|
|
|
|
/* One offset block in second revision */
|
|
onion_info.revision_num = 2;
|
|
fapl_id = H5Pcreate(H5P_FILE_ACCESS);
|
|
if (H5I_INVALID_HID == fapl_id)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
file = H5FDopen(paths->canon, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF);
|
|
if (NULL == file)
|
|
TEST_ERROR;
|
|
size = a_off + a_list_size_s;
|
|
if (size != H5FDget_eof(file, H5FD_MEM_DRAW)) {
|
|
printf("\nEOF is not %" PRIuHADDR ", it is: %" PRIuHADDR "\n", size,
|
|
H5FDget_eof(file, H5FD_MEM_DRAW));
|
|
TEST_ERROR;
|
|
}
|
|
if (NULL == (buf = malloc(size * sizeof(unsigned char))))
|
|
TEST_ERROR;
|
|
if (H5FDset_eoa(file, H5FD_MEM_DRAW, size) < 0)
|
|
TEST_ERROR;
|
|
if (H5FDread(file, H5FD_MEM_DRAW, H5P_DEFAULT, 0, size, buf) < 0)
|
|
TEST_ERROR;
|
|
for (i = 0; i < a_off; i++) {
|
|
if (0 != buf[i])
|
|
TEST_ERROR;
|
|
}
|
|
if (memcmp(buf + a_off, a_list_s, a_list_size_s) != 0)
|
|
TEST_ERROR;
|
|
free(buf);
|
|
buf = NULL;
|
|
/* Repeat read at page offset; test possible read offset error */
|
|
if (NULL == (buf = malloc(ONION_TEST_PAGE_SIZE_5 * sizeof(unsigned char))))
|
|
TEST_ERROR;
|
|
if (H5FDread(file, H5FD_MEM_DRAW, H5P_DEFAULT, ONION_TEST_PAGE_SIZE_5, ONION_TEST_PAGE_SIZE_5, buf) < 0)
|
|
TEST_ERROR;
|
|
size = a_off - ONION_TEST_PAGE_SIZE_5;
|
|
for (i = 0; i < size; i++) {
|
|
if (0 != buf[i])
|
|
TEST_ERROR;
|
|
}
|
|
if (memcmp(buf + size, a_list_s, ONION_TEST_PAGE_SIZE_5 - size) != 0)
|
|
TEST_ERROR;
|
|
free(buf);
|
|
buf = NULL;
|
|
if (H5FDclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = NULL;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
fapl_id = H5I_INVALID_HID;
|
|
|
|
/* Two offset blocks in third revision */
|
|
onion_info.revision_num = 3;
|
|
fapl_id = H5Pcreate(H5P_FILE_ACCESS);
|
|
if (H5I_INVALID_HID == fapl_id)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
file = H5FDopen(paths->canon, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF);
|
|
if (NULL == file)
|
|
TEST_ERROR;
|
|
size = b_off + b_list_size_s;
|
|
if (size != H5FDget_eof(file, H5FD_MEM_DRAW))
|
|
TEST_ERROR;
|
|
if (NULL == (buf = malloc(size * sizeof(unsigned char))))
|
|
TEST_ERROR;
|
|
if (H5FDset_eoa(file, H5FD_MEM_DRAW, size) < 0)
|
|
TEST_ERROR;
|
|
if (H5FDread(file, H5FD_MEM_DRAW, H5P_DEFAULT, 0, size, buf) < 0)
|
|
TEST_ERROR;
|
|
for (i = 0; i < a_off; i++) {
|
|
if (0 != buf[i])
|
|
TEST_ERROR;
|
|
}
|
|
if (memcmp(buf + a_off, a_list_s, a_list_size_s) != 0)
|
|
TEST_ERROR;
|
|
for (i = a_off + a_list_size_s; i < b_off; i++) {
|
|
if (0 != buf[i])
|
|
TEST_ERROR;
|
|
}
|
|
if (memcmp(buf + b_off, b_list_s, b_list_size_s) != 0)
|
|
TEST_ERROR;
|
|
free(buf);
|
|
buf = NULL;
|
|
if (H5FDclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = NULL;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
fapl_id = H5I_INVALID_HID;
|
|
|
|
/* From start and partial overwrite in fourth revision */
|
|
onion_info.revision_num = 4;
|
|
fapl_id = H5Pcreate(H5P_FILE_ACCESS);
|
|
if (H5I_INVALID_HID == fapl_id)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
file = H5FDopen(paths->canon, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF);
|
|
if (NULL == file)
|
|
TEST_ERROR;
|
|
size = b_off + b_list_size_s;
|
|
if (size != H5FDget_eof(file, H5FD_MEM_DRAW))
|
|
TEST_ERROR;
|
|
buf = (unsigned char *)malloc(sizeof(unsigned char) * size);
|
|
if (NULL == buf)
|
|
TEST_ERROR;
|
|
if (H5FDset_eoa(file, H5FD_MEM_DRAW, size) < 0)
|
|
TEST_ERROR;
|
|
if (H5FDread(file, H5FD_MEM_DRAW, H5P_DEFAULT, 0, size, buf) < 0)
|
|
TEST_ERROR;
|
|
if (memcmp(buf, a_list_s, a_list_size_s) != 0)
|
|
TEST_ERROR;
|
|
if (memcmp(buf + a_list_size_s, a_list_s + a_list_size_s - a_off, a_off) != 0)
|
|
TEST_ERROR;
|
|
for (i = a_off + a_list_size_s; i < b_off; i++) {
|
|
if (0 != buf[i])
|
|
TEST_ERROR;
|
|
}
|
|
if (memcmp(buf + b_off, b_list_s, b_list_size_s) != 0)
|
|
TEST_ERROR;
|
|
free(buf);
|
|
buf = NULL;
|
|
if (H5FDclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = NULL;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
fapl_id = H5I_INVALID_HID;
|
|
|
|
/* No fifth revision */
|
|
|
|
/* Inspect history construction */
|
|
|
|
file = H5FDopen(paths->onion, H5F_ACC_RDONLY, onion_info.backing_fapl_id, HADDR_UNDEF);
|
|
if (NULL == file)
|
|
TEST_ERROR;
|
|
|
|
filter.page_size = onion_info.page_size;
|
|
filter.n_revisions = 4;
|
|
filter.origin_eof = 0;
|
|
|
|
filter.revisions[0].comment = "first";
|
|
filter.revisions[0].n_index_entries = 0;
|
|
filter.revisions[0].revision_num = 0;
|
|
filter.revisions[0].parent_revision_num = 0;
|
|
filter.revisions[0].logical_eof = 0;
|
|
|
|
filter.revisions[1].comment = "second";
|
|
filter.revisions[1].n_index_entries = (a_list_size_s + ONION_TEST_PAGE_SIZE_5 - 1) >> 5;
|
|
filter.revisions[1].revision_num = 1;
|
|
filter.revisions[1].parent_revision_num = 0;
|
|
filter.revisions[1].logical_eof = a_off + a_list_size_s;
|
|
|
|
filter.revisions[2].comment = "third";
|
|
filter.revisions[2].n_index_entries =
|
|
filter.revisions[1].n_index_entries + ((b_list_size_s + ONION_TEST_PAGE_SIZE_5 - 1) >> 5);
|
|
filter.revisions[2].revision_num = 2;
|
|
filter.revisions[2].parent_revision_num = 1;
|
|
filter.revisions[2].logical_eof = b_off + b_list_size_s;
|
|
|
|
filter.revisions[3].comment = "fourth";
|
|
filter.revisions[3].n_index_entries = filter.revisions[2].n_index_entries + 1;
|
|
filter.revisions[3].revision_num = 3;
|
|
filter.revisions[3].parent_revision_num = 2;
|
|
filter.revisions[3].logical_eof = b_off + b_list_size_s;
|
|
|
|
if (verify_history_as_expected_onion(file, &filter) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5FDclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = NULL;
|
|
|
|
/* CLEANUP */
|
|
|
|
if (H5Pclose(onion_info.backing_fapl_id) < 0)
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
|
|
if (paths != NULL) {
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
}
|
|
|
|
free(history_out.record_locs);
|
|
free(buf);
|
|
|
|
if (file != NULL)
|
|
(void)H5FDclose(file);
|
|
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Pclose(fapl_id);
|
|
H5Pclose(onion_info.backing_fapl_id);
|
|
}
|
|
H5E_END_TRY
|
|
|
|
return -1;
|
|
} /* end test_several_revisions_with_logical_gaps() */
|
|
|
|
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
*
|
|
* Function: do_onion_open_and_writes
|
|
*
|
|
* Purpose: Automate the process of creating/opening a file and performing
|
|
* a series of writes.
|
|
*
|
|
* Return: Success : 0
|
|
* Failure : -1
|
|
*
|
|
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
*/
|
|
// TODO: Modify to create initial file without onion
|
|
static int
|
|
do_onion_open_and_writes(const char *filename, H5FD_onion_fapl_info_t *onion_info_p, size_t n_ops,
|
|
struct revise_revision *about)
|
|
{
|
|
hid_t fapl_id = H5I_INVALID_HID;
|
|
H5FD_t *file = NULL; /* Onion virtual file for read/write */
|
|
unsigned char *buf_vfy = NULL;
|
|
size_t i = 0;
|
|
|
|
for (i = 0; i < n_ops; i++) {
|
|
size_t j = 0;
|
|
unsigned int flags = H5F_ACC_RDWR;
|
|
|
|
if (i != 0 && about[i].truncate == true)
|
|
goto error;
|
|
|
|
if (true == about[i].truncate)
|
|
flags |= H5F_ACC_CREAT | H5F_ACC_TRUNC;
|
|
|
|
onion_info_p->revision_num = about[i].revision_num;
|
|
if (about[i].comment != NULL) {
|
|
j = MIN(strlen(about[i].comment), H5FD_ONION_FAPL_INFO_COMMENT_MAX_LEN);
|
|
memcpy(onion_info_p->comment, about[i].comment, j);
|
|
}
|
|
onion_info_p->comment[j] = '\0';
|
|
fapl_id = H5Pcreate(H5P_FILE_ACCESS);
|
|
if (H5I_INVALID_HID == fapl_id)
|
|
goto error;
|
|
if (H5Pset_fapl_onion(fapl_id, onion_info_p) < 0)
|
|
goto error;
|
|
file = H5FDopen(filename, flags, fapl_id, HADDR_UNDEF);
|
|
if (NULL == file)
|
|
goto error;
|
|
|
|
for (j = 0; j < about[i].n_writes; j++) {
|
|
struct write_info *wi = &about[i].writes[j];
|
|
|
|
/* Write to file */
|
|
if (H5FDget_eoa(file, H5FD_MEM_DRAW) < wi->offset + wi->size &&
|
|
H5FDset_eoa(file, H5FD_MEM_DRAW, wi->offset + wi->size) < 0)
|
|
TEST_ERROR;
|
|
if (H5FDwrite(file, H5FD_MEM_DRAW, H5P_DEFAULT, wi->offset, wi->size, wi->buf) < 0)
|
|
TEST_ERROR;
|
|
/* Verify write as expected */
|
|
if (NULL == (buf_vfy = malloc(wi->size * sizeof(unsigned char))))
|
|
TEST_ERROR;
|
|
if (H5FDread(file, H5FD_MEM_DRAW, H5P_DEFAULT, wi->offset, wi->size, buf_vfy) < 0)
|
|
TEST_ERROR;
|
|
if (memcmp(buf_vfy, wi->buf, wi->size) != 0) {
|
|
const unsigned char *_buf = wi->buf;
|
|
size_t z = 0;
|
|
puts("i exp act");
|
|
for (z = 0; z < wi->size; z++)
|
|
printf("%02zx %c %c\n", z, _buf[z], buf_vfy[z]);
|
|
fflush(stdout);
|
|
TEST_ERROR;
|
|
}
|
|
free(buf_vfy);
|
|
buf_vfy = NULL;
|
|
} /* end for each write */
|
|
|
|
if (H5FDclose(file) < 0)
|
|
goto error;
|
|
file = NULL;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
goto error;
|
|
fapl_id = H5I_INVALID_HID;
|
|
} /* end for each open-close cycle */
|
|
|
|
return 0;
|
|
|
|
error:
|
|
if (file != NULL)
|
|
(void)H5FDclose(file);
|
|
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Pclose(fapl_id);
|
|
}
|
|
H5E_END_TRY
|
|
|
|
free(buf_vfy);
|
|
|
|
return -1;
|
|
} /* end do_onion_open_and_writes() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* Function: test_page_aligned_history_create()
|
|
*
|
|
* Purpose: Verify that, when specified in FAPL on onionization/creation,
|
|
* All history writes are aligned to page-size boundaries.
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_page_aligned_history_create(void)
|
|
{
|
|
const char *basename = "somesuch";
|
|
hid_t fapl_id = H5I_INVALID_HID;
|
|
struct onion_filepaths *paths = NULL;
|
|
H5FD_onion_fapl_info_t onion_info = {
|
|
H5FD_ONION_FAPL_INFO_VERSION_CURR,
|
|
H5I_INVALID_HID, /* backing_fapl_id */
|
|
ONION_TEST_PAGE_SIZE_5, /* page_size */
|
|
H5FD_ONION_STORE_TARGET_ONION, /* store_target */
|
|
H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST,
|
|
0, /* force_write_open */
|
|
H5FD_ONION_FAPL_INFO_CREATE_FLAG_ENABLE_PAGE_ALIGNMENT,
|
|
"initial commit" /* comment */
|
|
};
|
|
H5FD_t *file = NULL; /* Onion virtual file for read/write */
|
|
unsigned char *buf = NULL;
|
|
struct revise_revision about[2];
|
|
H5FD_onion_header_t hdr_out;
|
|
H5FD_onion_history_t history_out;
|
|
size_t i = 0;
|
|
uint64_t a_off = b_list_size_s - a_list_size_s;
|
|
|
|
TESTING("page-aligned history on onion-created file");
|
|
|
|
/*********
|
|
* SETUP *
|
|
*********/
|
|
|
|
hdr_out.version = H5FD_ONION_HEADER_VERSION_CURR;
|
|
history_out.version = H5FD_ONION_HISTORY_VERSION_CURR;
|
|
history_out.n_revisions = 0;
|
|
history_out.record_locs = NULL;
|
|
|
|
if ((onion_info.backing_fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (NULL == (paths = onion_filepaths_init(basename)))
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
|
|
about[0].truncate = true;
|
|
about[0].revision_num = H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST;
|
|
about[0].comment = "initial_commit";
|
|
about[0].n_writes = 1;
|
|
about[0].writes[0].offset = 0;
|
|
about[0].writes[0].size = b_list_size_s;
|
|
about[0].writes[0].buf = b_list_s;
|
|
|
|
about[1].truncate = false;
|
|
about[1].revision_num = H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST;
|
|
about[1].comment = "second";
|
|
about[1].n_writes = 1;
|
|
about[1].writes[0].offset = a_off;
|
|
about[1].writes[0].size = a_list_size_s;
|
|
about[1].writes[0].buf = a_list_s;
|
|
|
|
if (do_onion_open_and_writes(paths->canon, &onion_info, 2, about) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Inspect logical file */
|
|
if (NULL == (buf = malloc(b_list_size_s * sizeof(unsigned char))))
|
|
TEST_ERROR;
|
|
file = H5FDopen(paths->canon, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF);
|
|
if (NULL == file)
|
|
TEST_ERROR;
|
|
if (b_list_size_s != H5FDget_eof(file, H5FD_MEM_DRAW))
|
|
TEST_ERROR;
|
|
if (H5FDset_eoa(file, H5FD_MEM_DRAW, b_list_size_s) < 0)
|
|
TEST_ERROR;
|
|
if (H5FDread(file, H5FD_MEM_DRAW, H5P_DEFAULT, 0, b_list_size_s, buf) < 0)
|
|
TEST_ERROR;
|
|
if (memcmp(a_list_s, buf + a_off, a_list_size_s) != 0) {
|
|
size_t k;
|
|
printf("aoff: %" PRIu64 "\n", a_off);
|
|
puts("i exp act");
|
|
for (k = 0; k < b_list_size_s; k++) {
|
|
printf("%3zu:: %c : %c\n", k, (k < a_off) ? ' ' : a_list_s[k - a_off], buf[k]);
|
|
}
|
|
fflush(stdout);
|
|
TEST_ERROR;
|
|
}
|
|
if (memcmp(b_list_s, buf, a_off) != 0) {
|
|
size_t k;
|
|
printf("aoff: %" PRIu64 "\n", a_off);
|
|
puts("i exp act");
|
|
for (k = 0; k < b_list_size_s; k++) {
|
|
printf("%3zu:: %c : %c\n", k, (k < a_off) ? b_list_s[k] : ' ', buf[k]);
|
|
}
|
|
fflush(stdout);
|
|
TEST_ERROR;
|
|
}
|
|
if (H5FDclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = NULL;
|
|
free(buf);
|
|
buf = NULL;
|
|
|
|
/* Inspect history construction */
|
|
|
|
if (NULL == (file = H5FDopen(paths->onion, H5F_ACC_RDONLY, onion_info.backing_fapl_id, HADDR_UNDEF)))
|
|
TEST_ERROR;
|
|
if (H5FDset_eoa(file, H5FD_MEM_DRAW, H5FDget_eof(file, H5FD_MEM_DRAW)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (NULL == (buf = malloc(H5FD_ONION_ENCODED_SIZE_HEADER)))
|
|
TEST_ERROR;
|
|
if (H5FDread(file, H5FD_MEM_DRAW, H5P_DEFAULT, 0, H5FD_ONION_ENCODED_SIZE_HEADER, buf) < 0)
|
|
TEST_ERROR;
|
|
if (H5FD__onion_header_decode(buf, &hdr_out) != H5FD_ONION_ENCODED_SIZE_HEADER)
|
|
TEST_ERROR;
|
|
if (hdr_out.history_addr & ((1 << 5) - 1)) /* 5::PAGE_SIZE_5 */
|
|
TEST_ERROR;
|
|
free(buf);
|
|
buf = NULL;
|
|
|
|
if (NULL == (buf = malloc(hdr_out.history_size)))
|
|
TEST_ERROR;
|
|
if (H5FDread(file, H5FD_MEM_DRAW, H5P_DEFAULT, hdr_out.history_addr, hdr_out.history_size, buf) < 0)
|
|
TEST_ERROR;
|
|
if (H5FD__onion_history_decode(buf, &history_out) != hdr_out.history_size)
|
|
TEST_ERROR;
|
|
if (history_out.n_revisions != 2)
|
|
TEST_ERROR;
|
|
history_out.record_locs = calloc(history_out.n_revisions, sizeof(H5FD_onion_record_loc_t));
|
|
if (NULL == history_out.record_locs)
|
|
TEST_ERROR;
|
|
if (H5FD__onion_history_decode(buf, &history_out) != hdr_out.history_size)
|
|
TEST_ERROR;
|
|
free(buf);
|
|
buf = NULL;
|
|
|
|
for (i = 0; i < history_out.n_revisions; i++) {
|
|
H5FD_onion_record_loc_t *rloc = &history_out.record_locs[i];
|
|
if (rloc->phys_addr & ((1 << 5) - 1)) /* 5::PAGE_SIZE_5 */
|
|
TEST_ERROR;
|
|
/* TODO: check phys_addr of each page entry? */
|
|
}
|
|
|
|
free(history_out.record_locs);
|
|
history_out.record_locs = NULL;
|
|
|
|
if (H5FDclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = NULL;
|
|
|
|
/* CLEANUP */
|
|
|
|
if (H5Pclose(onion_info.backing_fapl_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
|
|
free(buf);
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
|
|
if (paths != NULL) {
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
}
|
|
|
|
free(history_out.record_locs);
|
|
free(buf);
|
|
|
|
if (file != NULL)
|
|
(void)H5FDclose(file);
|
|
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Pclose(fapl_id);
|
|
H5Pclose(onion_info.backing_fapl_id);
|
|
}
|
|
H5E_END_TRY
|
|
|
|
return -1;
|
|
} /* end test_page_aligned_history_create() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* Function: test_integration_create()
|
|
*
|
|
* Purpose: Create and make multiple revisions in an HDF5 file.
|
|
*
|
|
* Return: PASSED : 0
|
|
* FAILED : -1
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
test_integration_create(void)
|
|
{
|
|
const char *basename = "integration_2d.h5";
|
|
hid_t fapl_id = H5I_INVALID_HID;
|
|
hid_t file_id = H5I_INVALID_HID;
|
|
hid_t file = H5I_INVALID_HID;
|
|
hid_t space = H5I_INVALID_HID;
|
|
hid_t dset = H5I_INVALID_HID;
|
|
hid_t dcpl = H5I_INVALID_HID;
|
|
struct onion_filepaths *paths = NULL;
|
|
H5FD_onion_fapl_info_t onion_info = {
|
|
H5FD_ONION_FAPL_INFO_VERSION_CURR,
|
|
H5I_INVALID_HID, /* backing_fapl_id */
|
|
ONION_TEST_PAGE_SIZE_5, /* page_size */
|
|
H5FD_ONION_STORE_TARGET_ONION, /* store_target */
|
|
H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST,
|
|
0, /* force_write_open */
|
|
0, /* creation flags, was H5FD_ONION_FAPL_INFO_CREATE_FLAG_ENABLE_PAGE_ALIGNMENT */
|
|
"initial commit" /* comment */
|
|
};
|
|
hsize_t dims[2] = {128, 256};
|
|
hsize_t maxdims[2] = {H5S_UNLIMITED, H5S_UNLIMITED};
|
|
hsize_t chunk[2] = {4, 4};
|
|
int fillval;
|
|
struct {
|
|
int arr[128][256];
|
|
} *wdata = NULL;
|
|
struct {
|
|
int arr[128][256];
|
|
} *rdata = NULL;
|
|
struct {
|
|
int arr[128][256];
|
|
} *dset_data = NULL;
|
|
|
|
TESTING("onion-created two dimensional HDF5 file with revisions");
|
|
|
|
/* SETUP */
|
|
|
|
if (NULL == (wdata = calloc(1, sizeof(*wdata))))
|
|
TEST_ERROR;
|
|
if (NULL == (rdata = calloc(1, sizeof(*rdata))))
|
|
TEST_ERROR;
|
|
if (NULL == (dset_data = calloc(1, sizeof(*dset_data))))
|
|
TEST_ERROR;
|
|
|
|
if ((onion_info.backing_fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (NULL == (paths = onion_filepaths_init(basename)))
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Create the skeleton file (create the file without Onion VFD)
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
|
|
/* Initialize data */
|
|
for (int i = 0; i < 128; i++)
|
|
for (int j = 0; j < 256; j++)
|
|
wdata->arr[i][j] = i * j - j;
|
|
|
|
/* Create a new file using the default properties */
|
|
if ((file = H5Fcreate(paths->canon, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create dataspace with unlimited dimensions */
|
|
if ((space = H5Screate_simple(2, dims, maxdims)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset creation property list, and set the chunk
|
|
* size
|
|
*/
|
|
if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_chunk(dcpl, 2, chunk) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Set the fill value for the dataset */
|
|
fillval = 99;
|
|
if (H5Pset_fill_value(dcpl, H5T_NATIVE_INT, &fillval) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Set the allocation time to "early". This way we can be sure
|
|
* that reading from the dataset immediately after creation will
|
|
* return the fill value.
|
|
*/
|
|
if (H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset using the dataset creation property list */
|
|
if ((dset = H5Dcreate2(file, "DS1", H5T_STD_I32LE, space, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Write the data to the dataset */
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Close and release resources */
|
|
if (H5Pclose(dcpl) < 0)
|
|
TEST_ERROR;
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
if (H5Sclose(space) < 0)
|
|
TEST_ERROR;
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* First revision: open the file with Onion VFD and change the data
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file_id = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((dset = H5Dopen2(file_id, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < 128; i++)
|
|
for (int j = 0; j < 256; j++)
|
|
dset_data->arr[i][j] = i * 6 + j + 1;
|
|
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset_data) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file_id) < 0)
|
|
TEST_ERROR;
|
|
file_id = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Second revision: open the file with Onion VFD and change the data
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file_id = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((dset = H5Dopen2(file_id, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < 128; i++)
|
|
for (int j = 0; j < 256; j++)
|
|
dset_data->arr[i][j] = i * 3 + j + 5;
|
|
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset_data) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* CLEANUP */
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file_id) < 0)
|
|
TEST_ERROR;
|
|
file_id = H5I_INVALID_HID;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
fapl_id = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Start to verify the revision
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
/*----------------------------------------------------------------------
|
|
* Verify the original file
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 0;
|
|
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((file_id = H5Fopen(paths->canon, H5F_ACC_RDONLY, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((dset = H5Dopen2(file_id, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dread(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < 128; i++) {
|
|
for (int j = 0; j < 256; j++) {
|
|
int expected = i * j - j;
|
|
if (rdata->arr[i][j] != expected) {
|
|
printf("ERROR!!! Expected: %d, Got: %d\n", expected, rdata->arr[i][j]);
|
|
fflush(stdout);
|
|
TEST_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file_id) < 0)
|
|
TEST_ERROR;
|
|
file_id = H5I_INVALID_HID;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
fapl_id = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Verify the first revision
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 1;
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((file_id = H5Fopen(paths->canon, H5F_ACC_RDONLY, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
if ((dset = H5Dopen2(file_id, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Dread(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < 128; i++) {
|
|
for (int j = 0; j < 256; j++) {
|
|
int expected = i * 6 + j + 1;
|
|
if (rdata->arr[i][j] != expected) {
|
|
printf("ERROR!!! Expected: %d, Got: %d\n", expected, rdata->arr[i][j]);
|
|
fflush(stdout);
|
|
TEST_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file_id) < 0)
|
|
TEST_ERROR;
|
|
file_id = H5I_INVALID_HID;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
fapl_id = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Verify the second revision
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 2;
|
|
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((file_id = H5Fopen(paths->canon, H5F_ACC_RDONLY, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
if ((dset = H5Dopen2(file_id, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Dread(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < 128; i++) {
|
|
for (int j = 0; j < 256; j++) {
|
|
int expected = i * 3 + j + 5;
|
|
if (rdata->arr[i][j] != expected) {
|
|
printf("ERROR!!! Expected: %d, Got: %d\n", expected, rdata->arr[i][j]);
|
|
fflush(stdout);
|
|
TEST_ERROR;
|
|
}
|
|
else {
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
if (H5Fclose(file_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Pclose(onion_info.backing_fapl_id) < 0)
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
|
|
free(wdata);
|
|
free(rdata);
|
|
free(dset_data);
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
|
|
if (paths != NULL) {
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
}
|
|
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Dclose(dset);
|
|
H5Fclose(file_id);
|
|
H5Pclose(fapl_id);
|
|
H5Pclose(onion_info.backing_fapl_id);
|
|
}
|
|
H5E_END_TRY
|
|
|
|
free(wdata);
|
|
free(rdata);
|
|
free(dset_data);
|
|
|
|
return -1;
|
|
} /* end test_integration_create() */
|
|
|
|
static int
|
|
test_integration_create_simple(void)
|
|
{
|
|
const char *basename = "integration_1d.h5";
|
|
hid_t fapl_id = H5I_INVALID_HID;
|
|
struct onion_filepaths *paths = NULL;
|
|
H5FD_onion_fapl_info_t onion_info = {
|
|
H5FD_ONION_FAPL_INFO_VERSION_CURR,
|
|
H5I_INVALID_HID, /* backing_fapl_id */
|
|
ONION_TEST_PAGE_SIZE_5, /* page_size */
|
|
H5FD_ONION_STORE_TARGET_ONION, /* store_target */
|
|
H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST,
|
|
0, /* force_write_open */
|
|
0, /* creation flags, was H5FD_ONION_FAPL_INFO_CREATE_FLAG_ENABLE_PAGE_ALIGNMENT */
|
|
"initial commit" /* comment */
|
|
};
|
|
hid_t file_id = H5I_INVALID_HID;
|
|
hid_t file = H5I_INVALID_HID;
|
|
hid_t space = H5I_INVALID_HID;
|
|
hid_t dset = H5I_INVALID_HID;
|
|
hid_t dcpl = H5I_INVALID_HID;
|
|
hsize_t dims[2] = {1, ONE_DIM_SIZE};
|
|
hsize_t maxdims[2] = {1, ONE_DIM_SIZE};
|
|
int fillval;
|
|
struct {
|
|
int arr[ONE_DIM_SIZE];
|
|
} *wdata = NULL;
|
|
struct {
|
|
int arr[ONE_DIM_SIZE];
|
|
} *rdata = NULL;
|
|
struct {
|
|
int arr[ONE_DIM_SIZE];
|
|
} *dset_data = NULL;
|
|
|
|
TESTING("onion-created one-dimensional HDF5 file with revisions");
|
|
|
|
/* Setup */
|
|
if (NULL == (wdata = calloc(1, sizeof(*wdata))))
|
|
TEST_ERROR;
|
|
if (NULL == (rdata = calloc(1, sizeof(*rdata))))
|
|
TEST_ERROR;
|
|
if (NULL == (dset_data = calloc(1, sizeof(*dset_data))))
|
|
TEST_ERROR;
|
|
|
|
if ((onion_info.backing_fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (NULL == (paths = onion_filepaths_init(basename)))
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Create the skeleton file (create the file without Onion VFD)
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
/* Initialize data */
|
|
for (int i = 0; i < ONE_DIM_SIZE; i++)
|
|
wdata->arr[i] = i;
|
|
|
|
/* Create a new file using the default properties */
|
|
if ((file = H5Fcreate(paths->canon, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create dataspace with unlimited dimensions*/
|
|
if ((space = H5Screate_simple(2, dims, maxdims)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset creation property list */
|
|
if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Set the fill value for the dataset */
|
|
fillval = 99;
|
|
if (H5Pset_fill_value(dcpl, H5T_NATIVE_INT, &fillval) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Set the allocation time to "early". This way we can be sure
|
|
* that reading from the dataset immediately after creation will
|
|
* return the fill value.
|
|
*/
|
|
if (H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset using the dataset creation property list */
|
|
if ((dset = H5Dcreate2(file, "DS1", H5T_STD_I32LE, space, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Write the data to the dataset */
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Close everything */
|
|
if (H5Pclose(dcpl) < 0)
|
|
TEST_ERROR;
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
if (H5Sclose(space) < 0)
|
|
TEST_ERROR;
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* First revision: open the file with Onion VFD and change the data
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file_id = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((dset = H5Dopen2(file_id, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < ONE_DIM_SIZE; i++)
|
|
dset_data->arr[i] = i + ONE_DIM_SIZE;
|
|
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset_data) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file_id) < 0)
|
|
TEST_ERROR;
|
|
file_id = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Second revision: open the file with Onion VFD and change the data
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file_id = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
if ((dset = H5Dopen2(file_id, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < ONE_DIM_SIZE; i++)
|
|
dset_data->arr[i] = i + 2048;
|
|
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset_data) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* CLEANUP */
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file_id) < 0)
|
|
TEST_ERROR;
|
|
file_id = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Third revision: open the file with Onion VFD and change the data
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file_id = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
if ((dset = H5Dopen2(file_id, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < ONE_DIM_SIZE; i += 20)
|
|
dset_data->arr[i] = i + 3072;
|
|
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset_data) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* CLEANUP */
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file_id) < 0)
|
|
TEST_ERROR;
|
|
file_id = H5I_INVALID_HID;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
fapl_id = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Start to verify the revision
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
/*----------------------------------------------------------------------
|
|
* Verify the second revision
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 2;
|
|
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((file_id = H5Fopen(paths->canon, H5F_ACC_RDONLY, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
if ((dset = H5Dopen2(file_id, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dread(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < ONE_DIM_SIZE; i += 20) {
|
|
int expected = i + 2048;
|
|
if (rdata->arr[i] != expected) {
|
|
printf("ERROR!!! Expected: %d, Got: %d\n", expected, rdata->arr[i]);
|
|
TEST_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Close everything */
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
if (H5Fclose(file_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(onion_info.backing_fapl_id) < 0)
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
|
|
free(wdata);
|
|
free(rdata);
|
|
free(dset_data);
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
|
|
if (paths != NULL) {
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
}
|
|
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Dclose(dset);
|
|
H5Fclose(file_id);
|
|
H5Pclose(fapl_id);
|
|
H5Pclose(onion_info.backing_fapl_id);
|
|
}
|
|
H5E_END_TRY
|
|
|
|
free(wdata);
|
|
free(rdata);
|
|
free(dset_data);
|
|
|
|
return -1;
|
|
} /* end test_integration_create_simple() */
|
|
|
|
static int
|
|
test_integration_create_delete_objects(void)
|
|
{
|
|
const char *basename = "integration_objs.h5";
|
|
hid_t fapl_id = H5I_INVALID_HID;
|
|
struct onion_filepaths *paths = NULL;
|
|
H5FD_onion_fapl_info_t onion_info = {
|
|
H5FD_ONION_FAPL_INFO_VERSION_CURR,
|
|
H5I_INVALID_HID, /* backing_fapl_id */
|
|
ONION_TEST_PAGE_SIZE_5, /* page_size */
|
|
H5FD_ONION_STORE_TARGET_ONION, /* store_target */
|
|
H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST,
|
|
0, /* force_write_open */
|
|
0, /* creation flags, was H5FD_ONION_FAPL_INFO_CREATE_FLAG_ENABLE_PAGE_ALIGNMENT */
|
|
"initial commit" /* comment */
|
|
};
|
|
hid_t group_id = H5I_INVALID_HID;
|
|
hid_t attr_space_id = H5I_INVALID_HID;
|
|
hid_t attr_id = H5I_INVALID_HID;
|
|
hsize_t attr_dim[1] = {4};
|
|
|
|
hid_t file = H5I_INVALID_HID;
|
|
hid_t space = H5I_INVALID_HID;
|
|
hid_t dset = H5I_INVALID_HID;
|
|
hid_t dcpl = H5I_INVALID_HID;
|
|
hsize_t dims[2] = {4, 4}, maxdims[2] = {H5S_UNLIMITED, H5S_UNLIMITED}, chunk[2] = {4, 4};
|
|
int wdata[4][4], /* Write buffer */
|
|
fillval, i, j;
|
|
|
|
TESTING("onion-created HDF5 file with revisions testing addition and deletion of objects");
|
|
|
|
/* Set up */
|
|
if ((onion_info.backing_fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (NULL == (paths = onion_filepaths_init(basename)))
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Create the skeleton file (create the file without Onion VFD)
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
|
|
/* Initialize data */
|
|
for (i = 0; i < 4; i++)
|
|
for (j = 0; j < 4; j++)
|
|
wdata[i][j] = i + j;
|
|
|
|
/* Create a new file using the default properties */
|
|
if ((file = H5Fcreate(paths->canon, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create dataspace with unlimited dimensions */
|
|
if ((space = H5Screate_simple(2, dims, maxdims)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset creation property list, and set the chunk
|
|
* size
|
|
*/
|
|
if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_chunk(dcpl, 2, chunk) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Set the fill value for the dataset */
|
|
fillval = 99;
|
|
if (H5Pset_fill_value(dcpl, H5T_NATIVE_INT, &fillval) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Set the allocation time to "early". This way we can be sure
|
|
* that reading from the dataset immediately after creation will
|
|
* return the fill value.
|
|
*/
|
|
if (H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset using the dataset creation property list */
|
|
if ((dset = H5Dcreate2(file, "DS1", H5T_STD_I32LE, space, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Write the data to the dataset */
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* First revision: open the file with Onion VFD and add a dataset (DS2) to the file
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset using the dataset creation property list */
|
|
if ((dset = H5Dcreate2(file, "DS2", H5T_STD_I32LE, space, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Write the data to the dataset */
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Second revision: open the file with Onion VFD and remove the dataset (DS2),
|
|
* which was added during the first revision.
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Ldelete(file, "DS2", H5P_DEFAULT) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Third revision: open the file with Onion VFD and add an attribute to the file
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create dataspace for attribute */
|
|
if ((attr_space_id = H5Screate_simple(1, attr_dim, NULL)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((attr_id =
|
|
H5Acreate2(file, "file_attribute", H5T_STD_I32LE, attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Sclose(attr_space_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Aclose(attr_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Fourth revision: open the file with Onion VFD and delete the attribute
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Adelete(file, "file_attribute") < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Fifth revision: open the file with Onion VFD and add a group to the file
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((group_id = H5Gcreate2(file, "new_group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Gclose(group_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Sixth revision: open the file with Onion VFD and delete the newly added group
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Ldelete(file, "new_group", H5P_DEFAULT) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Start to verify the revision
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
/*----------------------------------------------------------------------
|
|
* Verify the first revision: it should have the second dataset (DS2)
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 1;
|
|
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* The second dataset (DS2) should exist */
|
|
if (H5Lexists(file, "DS2", H5P_DEFAULT) <= 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*------------------------------------------------------------------------
|
|
* Verify the second revision: the second dataset (DS2) should be removed
|
|
*------------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 2;
|
|
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* The second dataset (DS2) shouldn't exist */
|
|
if (H5Lexists(file, "DS2", H5P_DEFAULT) > 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Verify the third revision: the file attribute (file_attribute) should exist
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 3;
|
|
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* The file attribute should exist */
|
|
if (H5Aexists(file, "file_attribute") <= 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Verify the fourth revision: the file attribute (file_attribute) should be removed
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 4;
|
|
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* The file attribute should be removed */
|
|
if (H5Aexists(file, "file_attribute") > 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Verify the fifth revision: the group (new_group) should exist
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 5;
|
|
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* The new group should exist */
|
|
if (H5Lexists(file, "new_group", H5P_DEFAULT) <= 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Verify the sixth revision: the group (new_group) should be removed
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 6;
|
|
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* The new group should exist */
|
|
if (H5Lexists(file, "new_group", H5P_DEFAULT) > 0)
|
|
TEST_ERROR;
|
|
|
|
/* Close everything */
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(dcpl) < 0)
|
|
TEST_ERROR;
|
|
if (H5Sclose(space) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(onion_info.backing_fapl_id) < 0)
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
|
|
if (paths != NULL) {
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
}
|
|
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Dclose(dset);
|
|
H5Fclose(file);
|
|
H5Pclose(fapl_id);
|
|
H5Sclose(space);
|
|
H5Pclose(onion_info.backing_fapl_id);
|
|
}
|
|
H5E_END_TRY
|
|
|
|
return -1;
|
|
} /* end test_integration_create_delete_objects */
|
|
|
|
static int
|
|
test_integration_dset_extension(void)
|
|
{
|
|
const char *basename = "integration_dset_ext.h5";
|
|
hid_t fapl_id = H5I_INVALID_HID;
|
|
struct onion_filepaths *paths = NULL;
|
|
H5FD_onion_fapl_info_t onion_info = {
|
|
H5FD_ONION_FAPL_INFO_VERSION_CURR,
|
|
H5I_INVALID_HID, /* backing_fapl_id */
|
|
ONION_TEST_PAGE_SIZE_5, /* page_size */
|
|
H5FD_ONION_STORE_TARGET_ONION, /* store_target */
|
|
H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST,
|
|
0, /* force_write_open */
|
|
0, /* creation flags, was H5FD_ONION_FAPL_INFO_CREATE_FLAG_ENABLE_PAGE_ALIGNMENT */
|
|
"initial commit" /* comment */
|
|
};
|
|
hid_t file = H5I_INVALID_HID;
|
|
hid_t space = H5I_INVALID_HID;
|
|
hid_t dset_space = H5I_INVALID_HID;
|
|
hid_t dset = H5I_INVALID_HID;
|
|
hid_t dcpl = H5I_INVALID_HID;
|
|
hsize_t dims[2] = {4, 4};
|
|
hsize_t maxdims[2] = {H5S_UNLIMITED, H5S_UNLIMITED};
|
|
hsize_t chunk[2] = {4, 4};
|
|
hsize_t size[2];
|
|
hsize_t offset[2];
|
|
int wdata[4][4]; /* Write buffer */
|
|
int fillval;
|
|
int rdata[4][4]; /* Read buffer */
|
|
|
|
TESTING("onion-created HDF5 file with revisions testing dataset extension");
|
|
|
|
/* Setup */
|
|
if ((onion_info.backing_fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (NULL == (paths = onion_filepaths_init(basename)))
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Create the skeleton file (create the file without Onion VFD)
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
|
|
/* Initialize data */
|
|
for (int i = 0; i < 4; i++)
|
|
for (int j = 0; j < 4; j++)
|
|
wdata[i][j] = i + j;
|
|
|
|
/* Create a new file using the default properties */
|
|
if ((file = H5Fcreate(paths->canon, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create dataspace with unlimited dimensions*/
|
|
if ((space = H5Screate_simple(2, dims, maxdims)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset creation property list, and set the chunk
|
|
* size
|
|
*/
|
|
if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_chunk(dcpl, 2, chunk) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Set the fill value for the dataset */
|
|
fillval = 99;
|
|
if (H5Pset_fill_value(dcpl, H5T_NATIVE_INT, &fillval) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Set the allocation time to "early". This way we can be sure
|
|
* that reading from the dataset immediately after creation will
|
|
* return the fill value.
|
|
*/
|
|
if (H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset using the dataset creation property list */
|
|
if ((dset = H5Dcreate2(file, "DS1", H5T_STD_I32LE, space, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Write the data to the dataset */
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* First revision: open the file with Onion VFD and extend the dataset
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Open the dataset */
|
|
if ((dset = H5Dopen2(file, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Extend the dataset and double the rows */
|
|
size[0] = 2 * dims[0];
|
|
size[1] = dims[1];
|
|
if (H5Dset_extent(dset, size) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((dset_space = H5Dget_space(dset)) < 0)
|
|
TEST_ERROR;
|
|
|
|
offset[0] = dims[0];
|
|
offset[1] = 0;
|
|
if (H5Sselect_hyperslab(dset_space, H5S_SELECT_SET, offset, NULL, dims, NULL) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Write the data to the dataset. */
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, space, dset_space, H5P_DEFAULT, wdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Sclose(dset_space) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Second revision: open the file with Onion VFD and shrink the dataset
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Open the dataset */
|
|
if ((dset = H5Dopen2(file, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Extend the dataset and shrink back the size */
|
|
if (H5Dset_extent(dset, dims) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Start to verify the revision
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
/*----------------------------------------------------------------------
|
|
* Verify the first revision: it should have the extended data
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 1;
|
|
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Open the dataset */
|
|
if ((dset = H5Dopen2(file, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((dset_space = H5Dget_space(dset)) < 0)
|
|
TEST_ERROR;
|
|
|
|
offset[0] = dims[0];
|
|
offset[1] = 0;
|
|
if (H5Sselect_hyperslab(dset_space, H5S_SELECT_SET, offset, NULL, dims, NULL) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dread(dset, H5T_NATIVE_INT, space, dset_space, H5P_DEFAULT, rdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
for (int j = 0; j < 4; j++)
|
|
if (rdata[i][j] != wdata[i][j])
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Verify the second revision: it should have the original data
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 2;
|
|
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Open the dataset */
|
|
dset = H5Dopen2(file, "DS1", H5P_DEFAULT);
|
|
|
|
if ((dset_space = H5Dget_space(dset)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dread(dset, H5T_NATIVE_INT, space, dset_space, H5P_DEFAULT, rdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
for (int j = 0; j < 4; j++)
|
|
if (rdata[i][j] != wdata[i][j])
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/* Close and release resources. */
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(dcpl) < 0)
|
|
TEST_ERROR;
|
|
if (H5Sclose(space) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(onion_info.backing_fapl_id) < 0)
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
|
|
if (paths != NULL) {
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
}
|
|
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Dclose(dset);
|
|
H5Fclose(file);
|
|
H5Pclose(fapl_id);
|
|
H5Pclose(onion_info.backing_fapl_id);
|
|
}
|
|
H5E_END_TRY
|
|
|
|
return -1;
|
|
} /* end test_integration_dset_extension */
|
|
|
|
static int
|
|
test_integration_ctl(void)
|
|
{
|
|
const char *basename = "integration_ctl.h5";
|
|
hid_t file = H5I_INVALID_HID;
|
|
hid_t space = H5I_INVALID_HID;
|
|
hid_t dset = H5I_INVALID_HID;
|
|
hid_t dcpl = H5I_INVALID_HID;
|
|
hid_t fapl_id = H5I_INVALID_HID;
|
|
hsize_t dims[2] = {4, 4};
|
|
hsize_t maxdims[2] = {H5S_UNLIMITED, H5S_UNLIMITED};
|
|
hsize_t chunk[2] = {4, 4};
|
|
int wdata[4][4]; /* Write buffer */
|
|
int fillval;
|
|
struct onion_filepaths *paths = NULL;
|
|
H5FD_onion_fapl_info_t onion_info = {
|
|
H5FD_ONION_FAPL_INFO_VERSION_CURR,
|
|
H5I_INVALID_HID, /* backing_fapl_id */
|
|
ONION_TEST_PAGE_SIZE_5, /* page_size */
|
|
H5FD_ONION_STORE_TARGET_ONION, /* store_target */
|
|
H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST,
|
|
0, /* force_write_open */
|
|
0, /* creation flags, was H5FD_ONION_FAPL_INFO_CREATE_FLAG_ENABLE_PAGE_ALIGNMENT */
|
|
"initial commit" /* comment */
|
|
};
|
|
uint64_t revision_count;
|
|
|
|
TESTING("onion-created HDF5 file with revisions testing H5FDctl");
|
|
|
|
/* Set up */
|
|
if ((onion_info.backing_fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (NULL == (paths = onion_filepaths_init(basename)))
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Create the skeleton file (create the file without Onion VFD)
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
|
|
/* Initialize data */
|
|
for (int i = 0; i < 4; i++)
|
|
for (int j = 0; j < 4; j++)
|
|
wdata[i][j] = i + j;
|
|
|
|
/* Create a new file using the default properties */
|
|
if ((file = H5Fcreate(paths->canon, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create dataspace with unlimited dimensions */
|
|
if ((space = H5Screate_simple(2, dims, maxdims)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset creation property list, and set the chunk size */
|
|
if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_chunk(dcpl, 2, chunk) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Set the fill value for the dataset */
|
|
fillval = 99;
|
|
if (H5Pset_fill_value(dcpl, H5T_NATIVE_INT, &fillval) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Set the allocation time to "early". This way we can be sure
|
|
* that reading from the dataset immediately after creation will
|
|
* return the fill value.
|
|
*/
|
|
if (H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset using the dataset creation property list */
|
|
if ((dset = H5Dcreate2(file, "DS1", H5T_STD_I32LE, space, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Write the data to the dataset */
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* First revision: open the file with Onion VFD and add a dataset (DS2) to the file
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset using the dataset creation property list */
|
|
if ((dset = H5Dcreate2(file, "DS2", H5T_STD_I32LE, space, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Write the data to the dataset */
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Second revision: open the file with Onion VFD and remove the dataset (DS2),
|
|
* which was added during the first revision.
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Ldelete(file, "DS2", H5P_DEFAULT) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Start to verify the number of revisions
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if (H5FDonion_get_revision_count(basename, fapl_id, &revision_count) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (2 != revision_count)
|
|
TEST_ERROR;
|
|
|
|
/* Close and release resources */
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(dcpl) < 0)
|
|
TEST_ERROR;
|
|
if (H5Sclose(space) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(onion_info.backing_fapl_id) < 0)
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
|
|
if (paths != NULL) {
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
}
|
|
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Dclose(dset);
|
|
H5Fclose(file);
|
|
H5Pclose(fapl_id);
|
|
H5Pclose(onion_info.backing_fapl_id);
|
|
}
|
|
H5E_END_TRY
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
test_integration_reference(void)
|
|
{
|
|
const char *basename = "integration_refer.h5";
|
|
hid_t file = H5I_INVALID_HID;
|
|
hid_t group = H5I_INVALID_HID;
|
|
hid_t space = H5I_INVALID_HID;
|
|
hid_t space2 = H5I_INVALID_HID;
|
|
hid_t space_ref = H5I_INVALID_HID;
|
|
hid_t dset = H5I_INVALID_HID;
|
|
hid_t dset2 = H5I_INVALID_HID;
|
|
hid_t fapl_id = H5I_INVALID_HID;
|
|
hsize_t dims[2] = {4, 4};
|
|
hsize_t dim_ref[1] = {2};
|
|
int wdata[4][4]; /* Write buffer */
|
|
int rdata[4][4]; /* Read buffer */
|
|
H5R_ref_t wbuf[2];
|
|
H5R_ref_t rbuf[2];
|
|
H5O_type_t obj_type;
|
|
hsize_t start[2];
|
|
hsize_t stride[2];
|
|
hsize_t count[2];
|
|
hsize_t block[2];
|
|
hsize_t coord1[4][2]; /* Coordinates for point selection */
|
|
hssize_t nelmts;
|
|
|
|
struct onion_filepaths *paths = NULL;
|
|
H5FD_onion_fapl_info_t onion_info = {
|
|
H5FD_ONION_FAPL_INFO_VERSION_CURR,
|
|
H5I_INVALID_HID, /* backing_fapl_id */
|
|
ONION_TEST_PAGE_SIZE_5, /* page_size */
|
|
H5FD_ONION_STORE_TARGET_ONION, /* store_target */
|
|
H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST,
|
|
0, /* force_write_open */
|
|
0, /* creation flags, was H5FD_ONION_FAPL_INFO_CREATE_FLAG_ENABLE_PAGE_ALIGNMENT */
|
|
"initial commit" /* comment */
|
|
};
|
|
|
|
TESTING("onion-created HDF5 file with revisions testing references");
|
|
|
|
/* Set up */
|
|
if ((onion_info.backing_fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (NULL == (paths = onion_filepaths_init(basename)))
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Create the skeleton file (create the file without Onion VFD)
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
|
|
/* Initialize data */
|
|
for (int i = 0; i < 4; i++)
|
|
for (int j = 0; j < 4; j++)
|
|
wdata[i][j] = i + j;
|
|
|
|
/* Create a new file using the default properties */
|
|
if ((file = H5Fcreate(paths->canon, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create dataspace */
|
|
if ((space = H5Screate_simple(2, dims, NULL)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset using the dataset creation property list */
|
|
if ((dset = H5Dcreate2(file, "DS1", H5T_STD_I32LE, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Write the data to the dataset */
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* First revision: open the file with Onion VFD and add a dataset (DS2)
|
|
* of object references
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create dataspace with unlimited dimensions */
|
|
if ((space_ref = H5Screate_simple(1, dim_ref, NULL)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset of object references */
|
|
if ((dset = H5Dcreate2(file, "DS2", H5T_STD_REF, space_ref, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create reference to dataset */
|
|
if (H5Rcreate_object(file, "DS1", H5P_DEFAULT, &wbuf[0]) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Rget_obj_type3(&wbuf[0], H5P_DEFAULT, &obj_type) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (obj_type != H5O_TYPE_DATASET)
|
|
TEST_ERROR;
|
|
|
|
/* Create reference to the root group */
|
|
if (H5Rcreate_object(file, "/", H5P_DEFAULT, &wbuf[1]) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Rget_obj_type3(&wbuf[1], H5P_DEFAULT, &obj_type) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (obj_type != H5O_TYPE_GROUP)
|
|
TEST_ERROR;
|
|
|
|
/* Write the object reference data to the dataset */
|
|
if (H5Dwrite(dset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
if (H5Rdestroy(&wbuf[i]) < 0)
|
|
TEST_ERROR;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Second revision: open the file with Onion VFD and add a dataset (DS3)
|
|
* of region references
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset of region references */
|
|
if ((dset = H5Dcreate2(file, "DS3", H5T_STD_REF, space_ref, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Select 2x4 hyperslab for first reference */
|
|
start[0] = 0;
|
|
start[1] = 0;
|
|
stride[0] = 1;
|
|
stride[1] = 1;
|
|
count[0] = 1;
|
|
count[1] = 1;
|
|
block[0] = 2;
|
|
block[1] = 4;
|
|
|
|
/* Make a hyperslab selection of 2x4 elements */
|
|
if (H5Sselect_hyperslab(space, H5S_SELECT_SET, start, stride, count, block) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Verify the number of selection */
|
|
if ((nelmts = H5Sget_select_npoints(space)) != 8) {
|
|
printf("Number of selected elements is supposed to be 8, but got %" PRIuHSIZE "\n", nelmts);
|
|
TEST_ERROR;
|
|
}
|
|
|
|
/* Store first data region */
|
|
if (H5Rcreate_region(file, "/DS1", space, H5P_DEFAULT, &wbuf[0]) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Rget_obj_type3(&wbuf[0], H5P_DEFAULT, &obj_type) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (obj_type != H5O_TYPE_DATASET)
|
|
TEST_ERROR;
|
|
|
|
/* Select the sequence of four points for the second reference */
|
|
coord1[0][0] = 0;
|
|
coord1[0][1] = 0;
|
|
coord1[1][0] = 1;
|
|
coord1[1][1] = 1;
|
|
coord1[2][0] = 2;
|
|
coord1[2][1] = 2;
|
|
coord1[3][0] = 3;
|
|
coord1[3][1] = 3;
|
|
|
|
if (H5Sselect_elements(space, H5S_SELECT_SET, 4, (const hsize_t *)coord1) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Store the second data region */
|
|
if (H5Rcreate_region(file, "/DS1", space, H5P_DEFAULT, &wbuf[1]) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Rget_obj_type3(&wbuf[1], H5P_DEFAULT, &obj_type) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (obj_type != H5O_TYPE_DATASET)
|
|
TEST_ERROR;
|
|
|
|
/* Write the region reference data to the dataset */
|
|
if (H5Dwrite(dset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
if (H5Rdestroy(&wbuf[i]) < 0)
|
|
TEST_ERROR;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Start to verify the revisions
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
/*----------------------------------------------------------------------
|
|
* Verify the first revision: it should have the object references
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 1;
|
|
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDONLY, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Open the dataset of the object references */
|
|
if ((dset = H5Dopen2(file, "DS2", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dread(dset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Open the referenced dataset and check the data */
|
|
if ((dset2 = H5Ropen_object(&rbuf[0], H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dread(dset2, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
for (int j = 0; j < 4; j++) {
|
|
int expected = i + j;
|
|
if (rdata[i][j] != expected) {
|
|
printf("ERROR!!! Expected: %d, Got: %d\n", expected, rdata[i][j]);
|
|
TEST_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Open the referenced group and make sure it's a group object */
|
|
if ((group = H5Ropen_object(&rbuf[1], H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5I_GROUP != H5Iget_type(group))
|
|
TEST_ERROR;
|
|
|
|
if (H5Gclose(group) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
|
|
if (H5Dclose(dset2) < 0)
|
|
TEST_ERROR;
|
|
dset2 = H5I_INVALID_HID;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
if (H5Rdestroy(&rbuf[i]) < 0)
|
|
TEST_ERROR;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Verify the second revision: it should have the region references
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
onion_info.revision_num = 2;
|
|
|
|
if (H5Pset_fapl_onion(fapl_id, &onion_info) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((file = H5Fopen(paths->canon, H5F_ACC_RDONLY, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Open the dataset of the region reference */
|
|
if ((dset = H5Dopen2(file, "DS3", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dread(dset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Get the hyperslab selection and check the referenced region of the dataset */
|
|
if ((space2 = H5Ropen_region(&rbuf[0], H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((nelmts = H5Sget_select_npoints(space2)) != 8) {
|
|
printf("Number of selected elements is supposed to be 8, but got %" PRIuHSIZE "\n", nelmts);
|
|
TEST_ERROR;
|
|
}
|
|
|
|
if (H5Sclose(space2) < 0)
|
|
TEST_ERROR;
|
|
space2 = H5I_INVALID_HID;
|
|
|
|
/* Get the element selection and check the referenced region of the dataset */
|
|
if ((space2 = H5Ropen_region(&rbuf[1], H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((nelmts = H5Sget_select_npoints(space2)) != 4) {
|
|
printf("Number of selected elements is supposed to be 4, but got %" PRIuHSIZE "\n", nelmts);
|
|
TEST_ERROR;
|
|
}
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
|
|
if (H5Sclose(space2) < 0)
|
|
TEST_ERROR;
|
|
space2 = H5I_INVALID_HID;
|
|
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
file = H5I_INVALID_HID;
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
if (H5Rdestroy(&rbuf[i]) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Close and release resources */
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Sclose(space) < 0)
|
|
TEST_ERROR;
|
|
if (H5Sclose(space_ref) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(onion_info.backing_fapl_id) < 0)
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
|
|
if (paths != NULL) {
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
}
|
|
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Dclose(dset);
|
|
H5Fclose(file);
|
|
H5Pclose(fapl_id);
|
|
H5Pclose(onion_info.backing_fapl_id);
|
|
}
|
|
H5E_END_TRY
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
test_integration_create_by_name(void)
|
|
{
|
|
const char *basename = "integration_by_name.h5";
|
|
hid_t fapl_id = H5I_INVALID_HID;
|
|
struct onion_filepaths *paths = NULL;
|
|
hid_t file_id = H5I_INVALID_HID;
|
|
hid_t file = H5I_INVALID_HID;
|
|
hid_t space = H5I_INVALID_HID;
|
|
hid_t dset = H5I_INVALID_HID;
|
|
hid_t dcpl = H5I_INVALID_HID;
|
|
hsize_t dims[2] = {1, ONE_DIM_SIZE};
|
|
hsize_t maxdims[2] = {1, ONE_DIM_SIZE};
|
|
int fillval;
|
|
struct {
|
|
int arr[ONE_DIM_SIZE];
|
|
} *wdata = NULL;
|
|
struct {
|
|
int arr[ONE_DIM_SIZE];
|
|
} *rdata = NULL;
|
|
struct {
|
|
int arr[ONE_DIM_SIZE];
|
|
} *dset_data = NULL;
|
|
|
|
TESTING("H5Pset_driver_by_name");
|
|
|
|
/* Setup */
|
|
if (NULL == (wdata = calloc(1, sizeof(*wdata))))
|
|
TEST_ERROR;
|
|
if (NULL == (rdata = calloc(1, sizeof(*rdata))))
|
|
TEST_ERROR;
|
|
if (NULL == (dset_data = calloc(1, sizeof(*dset_data))))
|
|
TEST_ERROR;
|
|
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Use H5Pset_driver_by_name to enable the Onion VFD */
|
|
if (H5Pset_driver_by_name(fapl_id, "onion", "{revision_num: H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST}") <
|
|
0)
|
|
TEST_ERROR;
|
|
|
|
if (NULL == (paths = onion_filepaths_init(basename)))
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Create the skeleton file (create the file without Onion VFD)
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
/* Initialize data */
|
|
for (int i = 0; i < ONE_DIM_SIZE; i++)
|
|
wdata->arr[i] = i;
|
|
|
|
/* Create a new file using the default properties */
|
|
if ((file = H5Fcreate(paths->canon, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create dataspace with unlimited dimensions*/
|
|
if ((space = H5Screate_simple(2, dims, maxdims)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset creation property list */
|
|
if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Set the fill value for the dataset */
|
|
fillval = 99;
|
|
if (H5Pset_fill_value(dcpl, H5T_NATIVE_INT, &fillval) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Set the allocation time to "early". This way we can be sure
|
|
* that reading from the dataset immediately after creation will
|
|
* return the fill value.
|
|
*/
|
|
if (H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Create the dataset using the dataset creation property list */
|
|
if ((dset = H5Dcreate2(file, "DS1", H5T_STD_I32LE, space, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Write the data to the dataset */
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* Close everything */
|
|
if (H5Pclose(dcpl) < 0)
|
|
TEST_ERROR;
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
if (H5Sclose(space) < 0)
|
|
TEST_ERROR;
|
|
if (H5Fclose(file) < 0)
|
|
TEST_ERROR;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* First revision: open the file with Onion VFD and change the data
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file_id = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((dset = H5Dopen2(file_id, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < ONE_DIM_SIZE; i++)
|
|
dset_data->arr[i] = i + ONE_DIM_SIZE;
|
|
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset_data) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file_id) < 0)
|
|
TEST_ERROR;
|
|
file_id = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Second revision: open the file with Onion VFD and change the data
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file_id = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
if ((dset = H5Dopen2(file_id, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < ONE_DIM_SIZE; i++)
|
|
dset_data->arr[i] = i + 2048;
|
|
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset_data) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* CLEANUP */
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file_id) < 0)
|
|
TEST_ERROR;
|
|
file_id = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Third revision: open the file with Onion VFD and change the data
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((file_id = H5Fopen(paths->canon, H5F_ACC_RDWR, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
if ((dset = H5Dopen2(file_id, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < ONE_DIM_SIZE; i += 20)
|
|
dset_data->arr[i] = i + 3072;
|
|
|
|
if (H5Dwrite(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset_data) < 0)
|
|
TEST_ERROR;
|
|
|
|
/* CLEANUP */
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
dset = H5I_INVALID_HID;
|
|
if (H5Fclose(file_id) < 0)
|
|
TEST_ERROR;
|
|
file_id = H5I_INVALID_HID;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
fapl_id = H5I_INVALID_HID;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Start to verify the revision with H5Pset_driver_by_name
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
/*----------------------------------------------------------------------
|
|
* Verify the second revision
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pset_driver_by_name(fapl_id, "onion", "{revision_num: 2; page_size: 4; }") < 0)
|
|
TEST_ERROR;
|
|
|
|
if ((file_id = H5Fopen(paths->canon, H5F_ACC_RDONLY, fapl_id)) < 0)
|
|
TEST_ERROR;
|
|
if ((dset = H5Dopen2(file_id, "DS1", H5P_DEFAULT)) < 0)
|
|
TEST_ERROR;
|
|
|
|
if (H5Dread(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata) < 0)
|
|
TEST_ERROR;
|
|
|
|
for (int i = 0; i < ONE_DIM_SIZE; i += 20) {
|
|
int expected = i + 2048;
|
|
if (rdata->arr[i] != expected) {
|
|
printf("ERROR!!! Expected: %d, Got: %d\n", expected, rdata->arr[i]);
|
|
TEST_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Close everything */
|
|
if (H5Dclose(dset) < 0)
|
|
TEST_ERROR;
|
|
if (H5Fclose(file_id) < 0)
|
|
TEST_ERROR;
|
|
if (H5Pclose(fapl_id) < 0)
|
|
TEST_ERROR;
|
|
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
|
|
free(wdata);
|
|
free(rdata);
|
|
free(dset_data);
|
|
|
|
PASSED();
|
|
return 0;
|
|
|
|
error:
|
|
|
|
if (paths != NULL) {
|
|
HDremove(paths->canon);
|
|
HDremove(paths->onion);
|
|
HDremove(paths->recovery);
|
|
onion_filepaths_destroy(paths);
|
|
}
|
|
|
|
H5E_BEGIN_TRY
|
|
{
|
|
H5Dclose(dset);
|
|
H5Fclose(file_id);
|
|
H5Pclose(fapl_id);
|
|
}
|
|
H5E_END_TRY
|
|
|
|
free(wdata);
|
|
free(rdata);
|
|
free(dset_data);
|
|
|
|
return -1;
|
|
} /* end test_integration_create_simple() */
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* Function: main()
|
|
*
|
|
* Purpose: Perform unit tests on for the Onion VFD.
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
int
|
|
main(void)
|
|
{
|
|
const char *driver_name; /* VFD value from environment */
|
|
int nerrors = 0;
|
|
|
|
printf("Testing Onion VFD functionality.\n");
|
|
|
|
h5_test_init();
|
|
|
|
/* The onion VFD only supports the sec2 VFD under the hood, so skip this
|
|
* test when the environment variable has been set to something else
|
|
*/
|
|
driver_name = h5_get_test_driver_name();
|
|
if (0 != strcmp(driver_name, "sec2")) {
|
|
SKIPPED();
|
|
puts("Onion VFD test skipped due to non-sec2 default VFD");
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
/* Initialize */
|
|
flags_create_s = H5F_ACC_RDWR | H5F_ACC_CREAT | H5F_ACC_TRUNC;
|
|
|
|
/* Run tests. Return values on error are negative. */
|
|
nerrors -= test_archival_index();
|
|
nerrors -= test_revision_index();
|
|
nerrors -= test_revision_index_collisions();
|
|
nerrors -= test_revision_index_resizing();
|
|
nerrors -= test_revision_index_to_archival_index();
|
|
nerrors -= test_fapl();
|
|
nerrors -= test_header_encode_decode();
|
|
nerrors -= test_history_encode_decode_empty();
|
|
nerrors -= test_history_encode_decode();
|
|
nerrors -= test_revision_record_encode_decode();
|
|
nerrors -= test_create_oniontarget(false, false);
|
|
nerrors -= test_create_oniontarget(true, false);
|
|
nerrors -= test_create_oniontarget(false, true);
|
|
nerrors -= test_create_oniontarget(true, true);
|
|
nerrors -= test_several_revisions_with_logical_gaps();
|
|
nerrors -= test_page_aligned_history_create();
|
|
nerrors -= test_integration_create();
|
|
nerrors -= test_integration_create_simple();
|
|
nerrors -= test_integration_create_delete_objects();
|
|
nerrors -= test_integration_dset_extension();
|
|
nerrors -= test_integration_ctl();
|
|
nerrors -= test_integration_reference();
|
|
nerrors -= test_integration_create_by_name();
|
|
|
|
if (nerrors > 0) {
|
|
printf("***** %d Onion TEST%s FAILED! *****\n", nerrors, nerrors > 1 ? "S" : "");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
printf("All Onion tests passed.\n");
|
|
return EXIT_SUCCESS;
|
|
|
|
} /* end main() */
|