diff options
-rw-r--r-- | src/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/H5FDonion.c | 1866 | ||||
-rw-r--r-- | src/H5FDonion_history.c | 480 | ||||
-rw-r--r-- | src/H5FDonion_history.h | 88 | ||||
-rw-r--r-- | src/H5FDonion_index.c | 934 | ||||
-rw-r--r-- | src/H5FDonion_index.h | 146 | ||||
-rw-r--r-- | src/H5FDonion_priv.h | 183 | ||||
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | test/onion.c | 451 |
9 files changed, 2122 insertions, 2035 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b1bd4a2..3ff3610 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -241,6 +241,8 @@ set (H5FD_SOURCES ${HDF5_SRC_DIR}/H5FDmpio.c ${HDF5_SRC_DIR}/H5FDmulti.c ${HDF5_SRC_DIR}/H5FDonion.c + ${HDF5_SRC_DIR}/H5FDonion_history.c + ${HDF5_SRC_DIR}/H5FDonion_index.c ${HDF5_SRC_DIR}/H5FDperform.c ${HDF5_SRC_DIR}/H5FDros3.c ${HDF5_SRC_DIR}/H5FDs3comms.c @@ -875,6 +877,8 @@ set (H5_PRIVATE_HEADERS ${HDF5_SRC_DIR}/H5FAprivate.h ${HDF5_SRC_DIR}/H5FDmirror_priv.h + ${HDF5_SRC_DIR}/H5FDonion_history.h + ${HDF5_SRC_DIR}/H5FDonion_index.h ${HDF5_SRC_DIR}/H5FDonion_priv.h ${HDF5_SRC_DIR}/H5FDpkg.h ${HDF5_SRC_DIR}/H5FDprivate.h diff --git a/src/H5FDonion.c b/src/H5FDonion.c index ae8483d..efcf945 100644 --- a/src/H5FDonion.c +++ b/src/H5FDonion.c @@ -63,7 +63,7 @@ static hid_t H5FD_ONION_g = 0; * * `backing_recov` (H5FD_t *) * - * Virtual file handle for the whole-history recovery file. + * Virtual file handle for the history recovery file. * * `name_recov` (char *) * @@ -84,9 +84,9 @@ static hid_t H5FD_ONION_g = 0; * * In-memory copy of the onion history data header. * - * `summary` (H5FD_onion_whole_history_t) + * `history` (H5FD_onion_history_t) * - * In-memory copy of the onion history "whole-history". + * In-memory copy of the onion history. * * `rev_record` (H5FD_onion_revision_record_t) * @@ -122,31 +122,28 @@ static hid_t H5FD_ONION_g = 0; ****************************************************************************** */ typedef struct H5FD_onion_t { - H5FD_t pub; - H5FD_onion_fapl_info_t fa; - H5FD_t * backing_canon; - H5FD_t * backing_onion; - H5FD_t * backing_recov; - char * name_recov; - hbool_t is_open_rw; - hbool_t page_align_history; - H5FD_onion_history_header_t header; - H5FD_onion_whole_history_t summary; - H5FD_onion_revision_record_t rev_record; - H5FD__onion_revision_index_t *rev_index; - haddr_t history_eof; - haddr_t origin_eof; - haddr_t logi_eoa; - haddr_t logi_eof; + H5FD_t pub; + H5FD_onion_fapl_info_t fa; + H5FD_t * backing_canon; + H5FD_t * backing_onion; + H5FD_t * backing_recov; + char * name_recov; + hbool_t is_open_rw; + hbool_t page_align_history; + H5FD_onion_history_header_t header; + H5FD_onion_history_t history; + H5FD_onion_revision_record_t rev_record; + H5FD_onion_revision_index_t *rev_index; + haddr_t history_eof; + haddr_t origin_eof; + haddr_t logi_eoa; + haddr_t logi_eof; } H5FD_onion_t; H5FL_DEFINE_STATIC(H5FD_onion_t); #define MAXADDR (((haddr_t)1 << (8 * sizeof(HDoff_t) - 1)) - 1) -/* 2^n for uint64_t types -- H5_EXP2 unsafe past 32 bits */ -#define U64_EXP2(n) ((uint64_t)1 << (n)) - #define H5FD_CTL__GET_NUM_REVISIONS 20001 /* Prototypes */ @@ -159,14 +156,7 @@ static herr_t H5FD__onion_set_eoa(H5FD_t *, H5FD_mem_t, haddr_t); static herr_t H5FD__onion_term(void); static herr_t H5FD__onion_write(H5FD_t *, H5FD_mem_t, hid_t, haddr_t, size_t, const void *); -static int H5FD__onion_archival_index_list_sort_cmp(const void *, const void *); -static herr_t H5FD__onion_ingest_whole_history(H5FD_onion_whole_history_t *whs_out, H5FD_t *raw_file, - haddr_t addr, haddr_t size); -static herr_t H5FD__onion_open_rw(H5FD_onion_t *, unsigned int, haddr_t, bool new_open); -static herr_t H5FD__onion_revision_index_resize(H5FD__onion_revision_index_t *); -static uint64_t H5FD__onion_whole_history_write(H5FD_onion_whole_history_t *whs, H5FD_t *file_dest, - haddr_t off_start, haddr_t filesize_curr); - +static herr_t H5FD__onion_open_rw(H5FD_onion_t *, unsigned int, haddr_t, bool new_open); static herr_t H5FD__onion_sb_encode(H5FD_t *_file, char *name /*out*/, unsigned char *buf /*out*/); static herr_t H5FD__onion_sb_decode(H5FD_t *_file, const char *name, const unsigned char *buf); static hsize_t H5FD__onion_sb_size(H5FD_t *_file); @@ -174,6 +164,9 @@ static herr_t H5FD__onion_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void H5_ATTR_UNUSED *input, void H5_ATTR_UNUSED **output); static herr_t H5FD__get_onion_revision_count(H5FD_t *file, size_t *revision_count); +/* Temporary */ +H5_DLL herr_t H5FD__onion_write_final_history(H5FD_onion_t *file); + static const H5FD_class_t H5FD_onion_g = { H5FD_CLASS_VERSION, /* struct version */ H5FD_ONION_VALUE, /* value */ @@ -286,15 +279,13 @@ H5Pget_fapl_onion(hid_t fapl_id, H5FD_onion_fapl_info_t *fa_out) if (NULL == fa_out) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL info-out pointer") - plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS); - if (NULL == plist) + if (NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Not a valid FAPL ID") if (H5FD_ONION != H5P_peek_driver(plist)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Incorrect VFL driver") - info_ptr = (const H5FD_onion_fapl_info_t *)H5P_peek_driver_info(plist); - if (NULL == info_ptr) + if (NULL == (info_ptr = (const H5FD_onion_fapl_info_t *)H5P_peek_driver_info(plist))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "bad VFL driver info") HDmemcpy(fa_out, info_ptr, sizeof(H5FD_onion_fapl_info_t)); @@ -337,14 +328,14 @@ H5Pset_fapl_onion(hid_t fapl_id, const H5FD_onion_fapl_info_t *fa) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid info page size") if (H5P_DEFAULT != fa->backing_fapl_id) { - H5P_genplist_t *_plist_ret = NULL; + H5P_genplist_t *backing_fapl = NULL; H5E_BEGIN_TRY { - _plist_ret = H5P_object_verify(fa->backing_fapl_id, H5P_FILE_ACCESS); + backing_fapl = H5P_object_verify(fa->backing_fapl_id, H5P_FILE_ACCESS); } H5E_END_TRY; - if (_plist_ret == NULL) + if (backing_fapl == NULL) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid backing fapl id") } @@ -355,83 +346,6 @@ done: } /* end H5Pset_fapl_onion() */ /*------------------------------------------------------------------------- - * Function: H5FDget_onion_revision_count - * - * Purpose: Get the number of revisions in an onion file - * - * Return: SUCCEED/FAIL - *------------------------------------------------------------------------- - */ -herr_t -H5FDonion_get_revision_count(const char *filename, hid_t fapl_id, size_t *revision_count /*out*/) -{ - H5P_genplist_t *plist = NULL; - H5FD_t * file = NULL; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_API(FAIL) - H5TRACE3("e", "*six", filename, fapl_id, revision_count); - - /* Check args */ - if (!filename || !HDstrcmp(filename, "")) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid file name") - if (!revision_count) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "revision count can't be null") - - /* Make sure using the correct driver */ - if (NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid FAPL ID") - if (H5FD_ONION != H5P_peek_driver(plist)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a Onion VFL driver") - - /* Open the file with the driver */ - if (NULL == (file = H5FD_open(filename, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF))) - HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, FAIL, "unable to open file with onion driver") - - /* Call the private function */ - if (H5FD__get_onion_revision_count(file, revision_count) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "failed to get the number of revisions") - -done: - /* Close H5FD_t structure pointer */ - if (file && H5FD_close(file) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, "unable to close file") - - FUNC_LEAVE_API(ret_value) -} - -/*------------------------------------------------------------------------- - * Function: H5FD__get_onion_revision_count - * - * Purpose: Private version of H5FDget_onion_revision_count() - * - * Return: SUCCEED/FAIL - *------------------------------------------------------------------------- - */ -static herr_t -H5FD__get_onion_revision_count(H5FD_t *file, size_t *revision_count) -{ - uint64_t op_code; - uint64_t flags; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_PACKAGE - - HDassert(file); - HDassert(revision_count); - - op_code = H5FD_CTL__GET_NUM_REVISIONS; - flags = H5FD_CTL__FAIL_IF_UNKNOWN_FLAG; - - /* Get the number of revisions via the ctl callback */ - if (H5FD_ctl(file, op_code, flags, NULL, (void **)&revision_count) < 0) - HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL, "VFD ctl request failed") - -done: - FUNC_LEAVE_NOAPI(ret_value) -} - -/*------------------------------------------------------------------------- * Function: H5FD__onion_sb_size * * Purpose: Returns the size of the private information to be stored in @@ -513,116 +427,6 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__onion_sb_decode */ -/*------------------------------------------------------------------------- - * Function: H5FD__onion_update_and_write_header - * - * Purpose: Write in-memory history header to appropriate backing file. - * Overwrites existing header data. - * - * Return: SUCCEED/FAIL - *------------------------------------------------------------------------- - */ -static herr_t -H5FD__onion_update_and_write_header(H5FD_onion_t *file) -{ - uint32_t _sum = 0; /* required */ - uint64_t size = 0; - unsigned char *buf = NULL; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_PACKAGE; - - /* Unset write-lock flag */ - if (file->is_open_rw) - file->header.flags &= (uint32_t)~H5FD__ONION_HEADER_FLAG_WRITE_LOCK; - - if (NULL == (buf = H5MM_malloc(H5FD__ONION_ENCODED_SIZE_HEADER))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer for updated history header") - - if (0 == (size = H5FD_onion_history_header_encode(&file->header, buf, &_sum))) - HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "problem encoding updated history header") - - if (H5FDwrite(file->backing_onion, H5FD_MEM_DRAW, H5P_DEFAULT, 0, (haddr_t)size, buf) < 0) - HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "can't write updated history header") - -done: - H5MM_xfree(buf); - - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD__onion_update_and_write_header()*/ - -/*----------------------------------------------------------------------------- - * Function: H5FD__onion_whole_history_write - * - * Purpose: Encode and write whole-history to file at the given address. - * - * Returns: Success: Number of bytes written to destination file (always non-zero) - * Failure: 0 - *----------------------------------------------------------------------------- - */ -static uint64_t -H5FD__onion_whole_history_write(H5FD_onion_whole_history_t *whs, H5FD_t *file_dest, haddr_t off_start, - haddr_t filesize_curr) -{ - uint32_t _sum = 0; /* Required by the API call but unused here */ - uint64_t size = 0; - unsigned char *buf = NULL; - uint64_t ret_value = 0; - - FUNC_ENTER_PACKAGE; - - if (NULL == (buf = H5MM_malloc(H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY + - (H5FD__ONION_ENCODED_SIZE_RECORD_POINTER * whs->n_revisions)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, 0, "can't allocate buffer for updated whole-history") - - if (0 == (size = H5FD_onion_whole_history_encode(whs, buf, &_sum))) - HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, 0, "problem encoding updated whole-history") - - if ((size + off_start > filesize_curr) && (H5FD_set_eoa(file_dest, H5FD_MEM_DRAW, off_start + size) < 0)) - HGOTO_ERROR(H5E_VFL, H5E_CANTSET, 0, "can't modify EOA for updated whole-history") - - if (H5FDwrite(file_dest, H5FD_MEM_DRAW, H5P_DEFAULT, off_start, size, buf) < 0) - HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, 0, "can't write whole-history as intended") - - ret_value = size; - -done: - H5MM_xfree(buf); - - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD__onion_whole_history_write() */ - -/*----------------------------------------------------------------------------- - * Write in-memory whole-history summary to appropriate backing file. - * Update information in other in-memory components. - *----------------------------------------------------------------------------- - */ -static herr_t -H5FD__onion_update_and_write_whole_history(H5FD_onion_t *file) -{ - uint64_t size = 0; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_PACKAGE; - - /* TODO: history EOF may not be correct (under what circumstances?) */ - - if (0 == (size = H5FD__onion_whole_history_write(&file->summary, file->backing_onion, file->history_eof, - file->history_eof))) - HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "can't write updated whole-history") - - if (size != file->header.whole_history_size) - HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "written whole-history differed from expected size") - - /* Is last write operation to history file; no need to extend to page - * boundary if set to page-align. - */ - file->history_eof += size; - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD__onion_update_and_write_whole_history() */ - /*----------------------------------------------------------------------------- * Write in-memory revision record to appropriate backing file. * Update information in other in-memory components. @@ -632,13 +436,13 @@ static herr_t H5FD__onion_commit_new_revision_record(H5FD_onion_t *file) { uint32_t _sum = 0; /* required */ - uint64_t size = 0; - uint64_t phys_addr = 0; /* offset in history file to record start */ + size_t size = 0; + haddr_t phys_addr = 0; /* offset in history file to record start */ unsigned char * buf = NULL; herr_t ret_value = SUCCEED; - H5FD_onion_revision_record_t *rec_p = &file->rev_record; - H5FD_onion_whole_history_t * whs_p = &file->summary; - H5FD_onion_record_pointer_t * new_list = NULL; + H5FD_onion_revision_record_t *rec = &file->rev_record; + H5FD_onion_history_t * history = &file->history; + H5FD_onion_record_loc_t * new_list = NULL; time_t rawtime; struct tm *info; @@ -647,25 +451,25 @@ H5FD__onion_commit_new_revision_record(H5FD_onion_t *file) HDtime(&rawtime); info = HDgmtime(&rawtime); - HDstrftime(rec_p->time_of_creation, sizeof(rec_p->time_of_creation), "%Y%m%dT%H%M%SZ", info); + HDstrftime(rec->time_of_creation, sizeof(rec->time_of_creation), "%Y%m%dT%H%M%SZ", info); - rec_p->logi_eof = file->logi_eof; + rec->logi_eof = file->logi_eof; - if ((TRUE == file->is_open_rw) && (H5FD_onion_merge_revision_index_into_archival_index( + if ((TRUE == file->is_open_rw) && (H5FD__onion_merge_revision_index_into_archival_index( file->rev_index, &file->rev_record.archival_index) < 0)) HGOTO_ERROR(H5E_VFL, H5E_INTERNAL, FAIL, "unable to update index to write") - if (NULL == (buf = H5MM_malloc(H5FD__ONION_ENCODED_SIZE_REVISION_RECORD + (size_t)rec_p->comment_size + - (H5FD__ONION_ENCODED_SIZE_INDEX_ENTRY * rec_p->archival_index.n_entries)))) + if (NULL == (buf = H5MM_malloc(H5FD__ONION_ENCODED_SIZE_REVISION_RECORD + (size_t)rec->comment_size + + (H5FD__ONION_ENCODED_SIZE_INDEX_ENTRY * rec->archival_index.n_entries)))) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer for encoded revision record") - if (0 == (size = H5FD_onion_revision_record_encode(rec_p, buf, &_sum))) + if (0 == (size = H5FD__onion_revision_record_encode(rec, buf, &_sum))) HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "problem encoding revision record") phys_addr = file->history_eof; if (H5FD_set_eoa(file->backing_onion, H5FD_MEM_DRAW, phys_addr + size) < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "can't modify EOA for new revision record") - if (H5FDwrite(file->backing_onion, H5FD_MEM_DRAW, H5P_DEFAULT, phys_addr, size, buf) < 0) + if (H5FD_write(file->backing_onion, H5FD_MEM_DRAW, phys_addr, size, buf) < 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "can't write new revision record") file->history_eof = phys_addr + size; @@ -673,48 +477,47 @@ H5FD__onion_commit_new_revision_record(H5FD_onion_t *file) file->history_eof = (file->history_eof + (file->header.page_size - 1)) & (~(file->header.page_size - 1)); - /* Update whole-history info to accommodate new revision */ + /* Update history info to accommodate new revision */ - if (whs_p->n_revisions == 0) { + if (history->n_revisions == 0) { unsigned char *ptr = buf; /* re-use buffer space to compute checksum */ - HDassert(whs_p->record_pointer_list == NULL); - whs_p->n_revisions = 1; - if (NULL == (whs_p->record_pointer_list = H5MM_calloc(sizeof(H5FD_onion_record_pointer_t)))) + HDassert(history->record_locs == NULL); + history->n_revisions = 1; + if (NULL == (history->record_locs = H5MM_calloc(sizeof(H5FD_onion_record_loc_t)))) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate temporary record pointer list") - whs_p->record_pointer_list[0].phys_addr = phys_addr; - whs_p->record_pointer_list[0].record_size = size; + history->record_locs[0].phys_addr = phys_addr; + history->record_locs[0].record_size = size; UINT64ENCODE(ptr, phys_addr); UINT64ENCODE(ptr, size); - whs_p->record_pointer_list[0].checksum = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); + history->record_locs[0].checksum = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); /* TODO: size-reset belongs where? */ - file->header.whole_history_size += H5FD__ONION_ENCODED_SIZE_RECORD_POINTER; + file->header.history_size += H5FD__ONION_ENCODED_SIZE_RECORD_POINTER; } /* end if no extant revisions in history */ else { unsigned char *ptr = buf; /* re-use buffer space to compute checksum */ - HDassert(whs_p->record_pointer_list != NULL); + HDassert(history->record_locs != NULL); - if (NULL == (new_list = H5MM_calloc((whs_p->n_revisions + 1) * sizeof(H5FD_onion_record_pointer_t)))) + if (NULL == (new_list = H5MM_calloc((history->n_revisions + 1) * sizeof(H5FD_onion_record_loc_t)))) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to resize record pointer list") - HDmemcpy(new_list, whs_p->record_pointer_list, - sizeof(H5FD_onion_record_pointer_t) * whs_p->n_revisions); - H5MM_xfree(whs_p->record_pointer_list); - whs_p->record_pointer_list = new_list; - new_list = NULL; - whs_p->record_pointer_list[whs_p->n_revisions].phys_addr = phys_addr; - whs_p->record_pointer_list[whs_p->n_revisions].record_size = size; + HDmemcpy(new_list, history->record_locs, sizeof(H5FD_onion_record_loc_t) * history->n_revisions); + H5MM_xfree(history->record_locs); + history->record_locs = new_list; + new_list = NULL; + history->record_locs[history->n_revisions].phys_addr = phys_addr; + history->record_locs[history->n_revisions].record_size = size; UINT64ENCODE(ptr, phys_addr); UINT64ENCODE(ptr, size); - whs_p->record_pointer_list[whs_p->n_revisions].checksum = + history->record_locs[history->n_revisions].checksum = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); - file->header.whole_history_size += H5FD__ONION_ENCODED_SIZE_RECORD_POINTER; - whs_p->n_revisions += 1; + file->header.history_size += H5FD__ONION_ENCODED_SIZE_RECORD_POINTER; + history->n_revisions += 1; } /* end if one or more revisions present in history */ - file->header.whole_history_addr = file->history_eof; + file->header.history_addr = file->history_eof; done: H5MM_xfree(buf); @@ -752,10 +555,13 @@ H5FD__onion_close(H5FD_t *_file) if (H5FD__onion_commit_new_revision_record(file) < 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "Can't write revision record to backing store") - if (H5FD__onion_update_and_write_whole_history(file) < 0) - HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "Can't write whole-history to backing store") + if (H5FD__onion_write_final_history(file) < 0) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "Can't write history to backing store") - if (H5FD__onion_update_and_write_header(file) < 0) + /* Unset write-lock flag */ + if (file->is_open_rw) + file->header.flags &= (uint32_t)~H5FD__ONION_HEADER_FLAG_WRITE_LOCK; + if (H5FD__onion_write_header(&(file->header), file->backing_onion) < 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "Can't write updated header to backing store") } } @@ -782,11 +588,11 @@ done: HDremove(file->name_recov); } if (file->rev_index) - if (H5FD_onion_revision_index_destroy(file->rev_index) < 0) + if (H5FD__onion_revision_index_destroy(file->rev_index) < 0) HDONE_ERROR(H5E_VFL, H5E_CANTRELEASE, FAIL, "can't close revision index") H5MM_xfree(file->name_recov); - H5MM_xfree(file->summary.record_pointer_list); + H5MM_xfree(file->history.record_locs); H5MM_xfree(file->rev_record.comment); H5MM_xfree(file->rev_record.archival_index.list); @@ -847,563 +653,22 @@ H5FD__onion_get_legit_fapl_id(hid_t fapl_id) } /*----------------------------------------------------------------------------- - * Function: H5FD_onion_history_header_decode - * - * Purpose: Attempt to read a buffer and store it as a history-header - * structure. - * - * Implementation must correspond with - * H5FD_onion_history_header_encode(). - * - * Return: Success: Number of bytes read from buffer - * Failure: 0 - *----------------------------------------------------------------------------- - */ -uint64_t -H5FD_onion_history_header_decode(unsigned char *buf, H5FD_onion_history_header_t *header) -{ - uint32_t ui32 = 0; - uint32_t sum = 0; - uint64_t ui64 = 0; - uint8_t * ui8p = NULL; - unsigned char *ptr = NULL; - uint64_t ret_value = 0; - - FUNC_ENTER_NOAPI_NOINIT; - - HDassert(buf != NULL); - HDassert(header != NULL); - HDassert(H5FD__ONION_HEADER_VERSION_CURR == header->version); - - if (HDstrncmp((const char *)buf, H5FD__ONION_HEADER_SIGNATURE, 4)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid header signature") - - if (buf[4] != H5FD__ONION_HEADER_VERSION_CURR) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid header version") - - ptr = buf + 5; - ui32 = 0; - HDmemcpy(&ui32, ptr, 3); - ui8p = (uint8_t *)&ui32; - UINT32DECODE(ui8p, header->flags); - ptr += 3; - - HDmemcpy(&ui32, ptr, 4); - ui8p = (uint8_t *)&ui32; - UINT32DECODE(ui8p, header->page_size); - ptr += 4; - - HDmemcpy(&ui64, ptr, 8); - ui8p = (uint8_t *)&ui64; - UINT32DECODE(ui8p, header->origin_eof); - ptr += 8; - - HDmemcpy(&ui64, ptr, 8); - ui8p = (uint8_t *)&ui64; - UINT32DECODE(ui8p, header->whole_history_addr); - ptr += 8; - - HDmemcpy(&ui64, ptr, 8); - ui8p = (uint8_t *)&ui64; - UINT32DECODE(ui8p, header->whole_history_size); - ptr += 8; - - sum = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); - - HDmemcpy(&ui32, ptr, 4); - ui8p = (uint8_t *)&ui32; - UINT32DECODE(ui8p, header->checksum); - ptr += 4; - - if (sum != header->checksum) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "checksum mismatch") - - ret_value = (uint64_t)(ptr - buf); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD_onion_history_header_decode() */ - -/*----------------------------------------------------------------------------- - * Function: H5FD_onion_history_header_encode - * - * Purpose: Write history-header structure to the given buffer. - * All multi-byte elements are stored in little-endian word order. - * - * Implementation must correspond with - * H5FD_onion_history_header_decode(). - * - * The destination buffer must be sufficiently large to hold the - * encoded contents (H5FD__ONION_ENCODED_SIZE_HEADER). - * - * Return: Number of bytes written to buffer. - * The checksum of the generated buffer contents (excluding the - * checksum itself) is stored in the pointer `sum_out`). - *----------------------------------------------------------------------------- - */ -uint64_t -H5FD_onion_history_header_encode(H5FD_onion_history_header_t *header, unsigned char *buf, uint32_t *sum_out) -{ - unsigned char *ptr = buf; - uint64_t ret_value = 0; - - FUNC_ENTER_NOAPI_NOINIT_NOERR; - - HDassert(buf != NULL); - HDassert(sum_out != NULL); - HDassert(header != NULL); - HDassert(H5FD__ONION_HEADER_VERSION_CURR == header->version); - HDassert(0 == (header->flags & 0xFF000000)); /* max three bits long */ - - HDmemcpy(ptr, H5FD__ONION_HEADER_SIGNATURE, 4); - ptr += 4; - HDmemcpy(ptr, (unsigned char *)&header->version, 1); - ptr += 1; - UINT32ENCODE(ptr, header->flags); - ptr -= 1; /* truncate to three bytes */ - UINT32ENCODE(ptr, header->page_size); - UINT64ENCODE(ptr, header->origin_eof); - UINT64ENCODE(ptr, header->whole_history_addr); - UINT64ENCODE(ptr, header->whole_history_size); - *sum_out = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); - UINT32ENCODE(ptr, *sum_out); - ret_value = (uint64_t)(ptr - buf); - - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD_onion_history_header_encode() */ - -/*----------------------------------------------------------------------------- - * Function: H5FD_onion_revision_record_decode - * - * Purpose: Attempt to read a buffer and store it as a revision record - * structure. + * Function: H5FD_onion_create_truncate_onion * - * Implementation must correspond with - * H5FD_onion_revision_record_encode(). + * Purpose: Create/truncate HDF5 and onion data for a fresh file * - * MUST BE CALLED TWICE: - * On the first call, n_entries and comment_size in the - * destination structure must all all be zero, and their - * respective variable-length components (index_entry_list, - * comment) must all be NULL. + * Special open operation required to instantiate the canonical file and + * history simultaneously. If successful, the required backing files are + * craeated and given initial population on the backing store, and the Onion + * virtual file handle is set; open effects a write-mode open. * - * If the buffer is well-formed, the destination structure is - * tentatively populated with fixed-size values, and the number of - * bytes read are returned. + * Cannot create 'template' history and proceed with normal write-mode open, + * as this would in effect create an empty first revision, making the history + * unintuitive. (create file -> initialize and commit empty first revision + * (revision 0); any data written to file during the 'create' open, as seen by + * the user, would be in the second revision (revision 1).) * - * Prior to the second call, the user must allocate space for the - * variable-length components, in accordance with the associated - * indicators (array of index-entry structures for - * index_entry_list, of size n_entries; character arrays for - * comment, allocated with the *_size number of bytes -- space - * for NULL-terminator is included in _size). - * - * Then the decode operation is called a second time, and all - * components will be populated (and again number of bytes read is - * returned). - * - * Return: Success: Number of bytes read from buffer - * Failure: 0 - *----------------------------------------------------------------------------- - */ -uint64_t -H5FD_onion_revision_record_decode(unsigned char *buf, H5FD_onion_revision_record_t *record) -{ - uint32_t ui32 = 0; - uint32_t page_size = 0; - uint32_t sum = 0; - uint64_t ui64 = 0; - uint64_t n_entries = 0; - uint32_t comment_size = 0; - uint8_t * ui8p = NULL; - unsigned char *ptr = NULL; - uint64_t ret_value = 0; - - FUNC_ENTER_NOAPI_NOINIT; - - HDassert(buf != NULL); - HDassert(record != NULL); - HDassert(H5FD__ONION_REVISION_RECORD_VERSION_CURR == record->version); - HDassert(H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR == record->archival_index.version); - - if (HDstrncmp((const char *)buf, H5FD__ONION_REVISION_RECORD_SIGNATURE, 4)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid signature") - - if (H5FD__ONION_REVISION_RECORD_VERSION_CURR != buf[4]) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid record version") - - ptr = buf + 8; - - HDmemcpy(&ui64, ptr, 8); - ui8p = (uint8_t *)&ui64; - UINT64DECODE(ui8p, record->revision_num); - ptr += 8; - - HDmemcpy(&ui64, ptr, 8); - ui8p = (uint8_t *)&ui64; - UINT64DECODE(ui8p, record->parent_revision_num); - ptr += 8; - - HDmemcpy(record->time_of_creation, ptr, 16); - ptr += 16; - - HDmemcpy(&ui64, ptr, 8); - ui8p = (uint8_t *)&ui64; - UINT64DECODE(ui8p, record->logi_eof); - ptr += 8; - - HDmemcpy(&ui32, ptr, 4); - ui8p = (uint8_t *)&ui32; - UINT32DECODE(ui8p, page_size); - ptr += 4; - - if (page_size == 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "page size is zero") - if (!POWER_OF_TWO(page_size)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "page size not power of two") - - for (record->archival_index.page_size_log2 = 0; - (((uint32_t)1 << record->archival_index.page_size_log2) & page_size) == 0; - record->archival_index.page_size_log2++) - ; - - HDmemcpy(&ui64, ptr, 8); - ui8p = (uint8_t *)&ui64; - UINT64DECODE(ui8p, n_entries); - ptr += 8; - - HDmemcpy(&ui32, ptr, 4); - ui8p = (uint8_t *)&ui32; - UINT32DECODE(ui8p, comment_size); - ptr += 4; - - if (record->archival_index.n_entries == 0) { - record->archival_index.n_entries = n_entries; - ptr += H5FD__ONION_ENCODED_SIZE_INDEX_ENTRY * n_entries; - } - else if (n_entries != record->archival_index.n_entries) { - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "n_entries in archival index does not match decoded") - } - else { - H5FD_onion_index_entry_t *entry_p = NULL; - size_t i = 0; - - if (record->archival_index.list == NULL) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "no archival index entry list") - - for (i = 0; i < n_entries; i++) { - entry_p = &record->archival_index.list[i]; - - HDmemcpy(&ui64, ptr, 8); - ui8p = (uint8_t *)&ui64; - UINT64DECODE(ui8p, entry_p->logi_page); - ptr += 8; - - /* logi_page actually encoded as address; check and convert */ - if (entry_p->logi_page & (page_size - 1)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "logical address does not align with page size") - - entry_p->logi_page = entry_p->logi_page >> record->archival_index.page_size_log2; - - HDmemcpy(&ui64, ptr, 8); - ui8p = (uint8_t *)&ui64; - UINT64DECODE(ui8p, entry_p->phys_addr); - ptr += 8; - - HDmemcpy(&ui32, ptr, 4); - ui8p = (uint8_t *)&ui32; - UINT32DECODE(ui8p, sum); - ptr += 4; - - ui32 = H5_checksum_fletcher32((ptr - 20), 16); - if (ui32 != sum) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "index entry checksum mismatch") - } - } - - if (record->comment_size == 0) { - if (record->comment != NULL) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "comment pointer prematurely allocated") - record->comment_size = comment_size; - } - else { - if (record->comment == NULL) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "no comment pointer") - HDmemcpy(record->comment, ptr, comment_size); - } - ptr += comment_size; - - sum = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); - - HDmemcpy(&ui32, ptr, 4); - ui8p = (uint8_t *)&ui32; - UINT32DECODE(ui8p, record->checksum); - ptr += 4; - - if (sum != record->checksum) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "checksum mismatch") - - ret_value = (uint64_t)(ptr - buf); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD_onion_revision_record_decode() */ - -/*----------------------------------------------------------------------------- - * Function: H5FD_onion_revision_record_encode - * - * Purpose: Write revision-record structure to the given buffer. - * All multi-byte elements are stored in little-endian word order. - * - * Implementation must correspond with - * H5FD_onion_revision_record_decode(). - * - * The destination buffer must be sufficiently large to hold the - * encoded contents. - * (Hint: `sizeof(revision-record-struct) + comment-size + - * sizeof(index-entry-struct) * n_entries)` - * guarantees ample/excess space.) - * - * Return: Number of bytes written to buffer. - * The checksum of the generated buffer contents (excluding the - * checksum itself) is stored in the pointer `sum_out`). - *----------------------------------------------------------------------------- - */ -uint64_t -H5FD_onion_revision_record_encode(H5FD_onion_revision_record_t *record, unsigned char *buf, uint32_t *sum_out) -{ - unsigned char *ptr = buf; /* original pointer */ - uint32_t vers_u32 = (uint32_t)record->version; /* pad out unused bytes */ - uint32_t page_size = 0; - - FUNC_ENTER_NOAPI_NOINIT_NOERR; - - HDassert(sum_out != NULL); - HDassert(buf != NULL); - HDassert(record != NULL); - HDassert(vers_u32 < 0x100); - HDassert(H5FD__ONION_REVISION_RECORD_VERSION_CURR == record->version); - HDassert(H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR == record->archival_index.version); - - page_size = (uint32_t)(1 << record->archival_index.page_size_log2); - - HDmemcpy(ptr, H5FD__ONION_REVISION_RECORD_SIGNATURE, 4); - ptr += 4; - UINT32ENCODE(ptr, vers_u32); - UINT64ENCODE(ptr, record->revision_num); - UINT64ENCODE(ptr, record->parent_revision_num); - HDmemcpy(ptr, record->time_of_creation, 16); - ptr += 16; - UINT64ENCODE(ptr, record->logi_eof); - UINT32ENCODE(ptr, page_size); - UINT64ENCODE(ptr, record->archival_index.n_entries); - UINT32ENCODE(ptr, record->comment_size); - - if (record->archival_index.n_entries > 0) { - uint64_t i = 0; - uint64_t page_size_log2 = record->archival_index.page_size_log2; - - HDassert(record->archival_index.list != NULL); - for (i = 0; i < record->archival_index.n_entries; i++) { - uint32_t sum = 0; - H5FD_onion_index_entry_t *entry_p = NULL; - uint64_t logi_addr = 0; - - entry_p = &record->archival_index.list[i]; - logi_addr = entry_p->logi_page << page_size_log2; - - UINT64ENCODE(ptr, logi_addr); - UINT64ENCODE(ptr, entry_p->phys_addr); - sum = H5_checksum_fletcher32((ptr - 16), 16); - UINT32ENCODE(ptr, sum); - } - } - - if (record->comment_size > 0) { - HDassert(record->comment != NULL && *record->comment != '\0'); - HDmemcpy(ptr, record->comment, record->comment_size); - ptr += record->comment_size; - } - - *sum_out = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); - UINT32ENCODE(ptr, *sum_out); - - FUNC_LEAVE_NOAPI((uint64_t)(ptr - buf)); -} /* end H5FD_onion_revision_record_encode() */ - -/*----------------------------------------------------------------------------- - * Function: H5FD_onion_whole_history_decode - * - * Purpose: Attempt to read a buffer and store it as a whole-history - * structure. - * - * Implementation must correspond with - * H5FD_onion_whole_history_encode(). - * - * MUST BE CALLED TWICE: - * On the first call, n_records in the destination structure must - * be zero, and record_pointer_list be NULL. - * - * If the buffer is well-formed, the destination structure is - * tentatively populated with fixed-size values, and the number of - * bytes read are returned. - * - * Prior to the second call, the user must allocate space for - * record_pointer_list to hold n_records record-pointer structs. - * - * Then the decode operation is called a second time, and all - * components will be populated (and again number of bytes read is - * returned). - * - * Return: Success: Number of bytes read from buffer - * Failure: 0 - *----------------------------------------------------------------------------- - */ -uint64_t -H5FD_onion_whole_history_decode(unsigned char *buf, H5FD_onion_whole_history_t *summary) -{ - uint32_t ui32 = 0; - uint32_t sum = 0; - uint64_t ui64 = 0; - uint64_t n_revisions = 0; - uint8_t * ui8p = NULL; - unsigned char *ptr = NULL; - uint64_t ret_value = 0; - - FUNC_ENTER_NOAPI_NOINIT; - - HDassert(buf != NULL); - HDassert(summary != NULL); - HDassert(H5FD__ONION_WHOLE_HISTORY_VERSION_CURR == summary->version); - - if (HDstrncmp((const char *)buf, "OWHS", 4)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid signature") - - if (H5FD__ONION_WHOLE_HISTORY_VERSION_CURR != buf[4]) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid version") - - ptr = buf + 8; - - HDmemcpy(&ui64, ptr, 8); - ui8p = (uint8_t *)&ui64; - UINT64DECODE(ui8p, n_revisions); - ptr += 8; - - if (0 == summary->n_revisions) { - summary->n_revisions = n_revisions; - ptr += H5FD__ONION_ENCODED_SIZE_RECORD_POINTER * n_revisions; - } - else { - uint64_t i = 0; - - if (summary->n_revisions != n_revisions) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, - "summary argument suggests different revision count than encoded buffer") - if (NULL == summary->record_pointer_list) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "list is NULL -- cannot populate") - - for (i = 0; i < n_revisions; i++) { - H5FD_onion_record_pointer_t *rpp = &summary->record_pointer_list[i]; - - HDmemcpy(&ui64, ptr, 8); - ui8p = (uint8_t *)&ui64; - UINT64DECODE(ui8p, rpp->phys_addr); - ptr += 8; - - HDmemcpy(&ui64, ptr, 8); - ui8p = (uint8_t *)&ui64; - UINT64DECODE(ui8p, rpp->record_size); - ptr += 8; - - HDmemcpy(&ui32, ptr, 4); - ui8p = (uint8_t *)&ui32; - UINT64DECODE(ui8p, rpp->checksum); - ptr += 4; - } - } - - sum = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); - - HDmemcpy(&ui32, ptr, 4); - ui8p = (uint8_t *)&ui32; - UINT32DECODE(ui8p, summary->checksum); - ptr += 4; - - if (sum != summary->checksum) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "checksum mismatch") - - ret_value = (uint64_t)(ptr - buf); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD_onion_whole_history_decode() */ - -/*----------------------------------------------------------------------------- - * Function: H5FD_onion_whole_history_encode - * - * Purpose: Write whole-history structure to the given buffer. - * All multi-byte elements are stored in little-endian word order. - * - * Implementation must correspond with - * H5FD_onion_whole_history_decode(). - * - * The destination buffer must be sufficiently large to hold the - * encoded contents. - * (Hint: `sizeof(whole-history-struct) + - * sizeof(record-pointer-struct) * n_records)` guarantees - * ample/excess space.) - * - * Return: Number of bytes written to buffer. - * The checksum of the generated buffer contents (excluding the - * checksum itself) is stored in the pointer `sum_out`). - *----------------------------------------------------------------------------- - */ -uint64_t -H5FD_onion_whole_history_encode(H5FD_onion_whole_history_t *summary, unsigned char *buf, uint32_t *sum_out) -{ - unsigned char *ptr = buf; - uint32_t vers_u32 = (uint32_t)summary->version; /* pad out unused bytes */ - - FUNC_ENTER_NOAPI_NOINIT_NOERR; - - HDassert(summary != NULL); - HDassert(H5FD__ONION_WHOLE_HISTORY_VERSION_CURR == summary->version); - HDassert(buf != NULL); - HDassert(sum_out != NULL); - - HDmemcpy(ptr, H5FD__ONION_WHOLE_HISTORY_SIGNATURE, 4); - ptr += 4; - UINT32ENCODE(ptr, vers_u32); - UINT64ENCODE(ptr, summary->n_revisions); - if (summary->n_revisions > 0) { - uint64_t i = 0; - - HDassert(summary->record_pointer_list != NULL); /* TODO: error? */ - for (i = 0; i < summary->n_revisions; i++) { - UINT64ENCODE(ptr, summary->record_pointer_list[i].phys_addr); - UINT64ENCODE(ptr, summary->record_pointer_list[i].record_size); - UINT32ENCODE(ptr, summary->record_pointer_list[i].checksum); - } - } - *sum_out = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); - UINT32ENCODE(ptr, *sum_out); - - FUNC_LEAVE_NOAPI((uint64_t)(ptr - buf)); -} /* end H5FD_onion_whole_history_encode() */ - -/*----------------------------------------------------------------------------- - * Create/truncate HDF5 and onion data for a fresh file. - * - * Special open operation required to instantiate the canonical file and - * history simultaneously. If successful, the required backing files are - * craeated and given initial population on the backing store, and the Onion - * virtual file handle is set; open effects a write-mode open. - * - * Cannot create 'template' history and proceed with normal write-mode open, - * as this would in effect create an empty first revision, making the history - * unintuitive. (create file -> initialize and commit empty first revision - * (revision 0); any data written to file during the 'create' open, as seen by - * the user, would be in the second revision (revision 1).) + * Return: SUCCEED/FAIL *----------------------------------------------------------------------------- */ static herr_t @@ -1411,9 +676,9 @@ H5FD__onion_create_truncate_onion(H5FD_onion_t *file, const char *filename, cons const char *name_recovery, unsigned int flags, haddr_t maxaddr) { hid_t backing_fapl_id = H5I_INVALID_HID; - H5FD_onion_history_header_t * hdr_p = NULL; - H5FD_onion_whole_history_t * whs_p = NULL; - H5FD_onion_revision_record_t *rec_p = NULL; + H5FD_onion_history_header_t * hdr = NULL; + H5FD_onion_history_t * history = NULL; + H5FD_onion_revision_record_t *rec = NULL; unsigned char * buf = NULL; uint64_t size = 0; herr_t ret_value = SUCCEED; @@ -1422,17 +687,17 @@ H5FD__onion_create_truncate_onion(H5FD_onion_t *file, const char *filename, cons HDassert(file != NULL); - hdr_p = &file->header; - whs_p = &file->summary; - rec_p = &file->rev_record; + hdr = &file->header; + history = &file->history; + rec = &file->rev_record; - hdr_p->flags = H5FD__ONION_HEADER_FLAG_WRITE_LOCK; + hdr->flags = H5FD__ONION_HEADER_FLAG_WRITE_LOCK; if (H5FD_ONION_FAPL_INFO_CREATE_FLAG_ENABLE_DIVERGENT_HISTORY & file->fa.creation_flags) - hdr_p->flags |= H5FD__ONION_HEADER_FLAG_DIVERGENT_HISTORY; + hdr->flags |= H5FD__ONION_HEADER_FLAG_DIVERGENT_HISTORY; if (H5FD_ONION_FAPL_INFO_CREATE_FLAG_ENABLE_PAGE_ALIGNMENT & file->fa.creation_flags) - hdr_p->flags |= H5FD__ONION_HEADER_FLAG_PAGE_ALIGNMENT; + hdr->flags |= H5FD__ONION_HEADER_FLAG_PAGE_ALIGNMENT; - hdr_p->origin_eof = 0; + hdr->origin_eof = 0; backing_fapl_id = H5FD__onion_get_legit_fapl_id(file->fa.backing_fapl_id); if (H5I_INVALID_HID == backing_fapl_id) @@ -1453,51 +718,44 @@ H5FD__onion_create_truncate_onion(H5FD_onion_t *file, const char *filename, cons if (H5FD_set_eoa(file->backing_canon, H5FD_MEM_DRAW, 8) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't extend EOA") - /* must use public API to correctly set DXPL context :( */ - if (H5FDwrite(file->backing_canon, H5FD_MEM_DRAW, H5P_DEFAULT, 0, 8, "ONIONEOF") < 0) + if (H5FD_write(file->backing_canon, H5FD_MEM_DRAW, 0, 8, "ONIONEOF") < 0) HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "cannot write header to the backing h5 file") - /* Write nascent whole-history summary (with no revisions) to "recovery" */ + /* Write nascent history (with no revisions) to "recovery" */ if (NULL == (buf = H5MM_malloc(H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY))) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer") - size = H5FD_onion_whole_history_encode(whs_p, buf, &whs_p->checksum); + size = H5FD__onion_history_encode(history, buf, &history->checksum); if (H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY != size) - HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't encode whole-history") + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't encode history") if (H5FD_set_eoa(file->backing_recov, H5FD_MEM_DRAW, size) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't extend EOA") - /* Must use public API to correctly set DXPL context :( - * TODO: Revisit this... - */ - if (H5FDwrite(file->backing_recov, H5FD_MEM_DRAW, H5P_DEFAULT, 0, size, buf) < 0) - HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "cannot write summary to the backing recovery file") - hdr_p->whole_history_size = size; /* record for later use */ + if (H5FD_write(file->backing_recov, H5FD_MEM_DRAW, 0, size, buf) < 0) + HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "cannot write history to the backing recovery file") + hdr->history_size = size; /* record for later use */ H5MM_xfree(buf); buf = NULL; - /* Write history header with "no" whole-history summary to history. + /* Write history header with "no" history. * Size of the "recovery" history recorded for later use on close. */ if (NULL == (buf = H5MM_malloc(H5FD__ONION_ENCODED_SIZE_HEADER))) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer") - size = H5FD_onion_history_header_encode(hdr_p, buf, &hdr_p->checksum); + size = H5FD__onion_history_header_encode(hdr, buf, &hdr->checksum); if (H5FD__ONION_ENCODED_SIZE_HEADER != size) HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't encode history header") if (H5FD_set_eoa(file->backing_onion, H5FD_MEM_DRAW, size) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't extend EOA") - /* Must use public API to correctly set DXPL context :( - * TODO: Revisit this... - */ - if (H5FDwrite(file->backing_onion, H5FD_MEM_DRAW, H5P_DEFAULT, 0, size, buf) < 0) + if (H5FD_write(file->backing_onion, H5FD_MEM_DRAW, 0, size, buf) < 0) HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "cannot write header to the backing onion file") file->history_eof = (haddr_t)size; if (TRUE == file->page_align_history) - file->history_eof = (file->history_eof + (hdr_p->page_size - 1)) & (~(hdr_p->page_size - 1)); + file->history_eof = (file->history_eof + (hdr->page_size - 1)) & (~(hdr->page_size - 1)); - rec_p->archival_index.list = NULL; + rec->archival_index.list = NULL; - if (NULL == (file->rev_index = H5FD_onion_revision_index_init(file->fa.page_size))) + if (NULL == (file->rev_index = H5FD__onion_revision_index_init(file->fa.page_size))) HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize revision index") done: @@ -1510,234 +768,6 @@ done: } /* end H5FD__onion_create_truncate_onion() */ /*----------------------------------------------------------------------------- - * Read and decode the history header information from `raw_file` at `addr`, - * and store the decoded information in the structure at `hdr_out`. - *----------------------------------------------------------------------------- - */ -static herr_t -H5FD__onion_ingest_history_header(H5FD_onion_history_header_t *hdr_out, H5FD_t *raw_file, haddr_t addr) -{ - unsigned char *buf = NULL; - herr_t ret_value = SUCCEED; - haddr_t size = (haddr_t)H5FD__ONION_ENCODED_SIZE_HEADER; - uint32_t sum = 0; - - FUNC_ENTER_PACKAGE; - - if (H5FD_get_eof(raw_file, H5FD_MEM_DRAW) < (addr + size)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "header indicates whole-history beyond EOF") - - if (NULL == (buf = H5MM_malloc(sizeof(char) * size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer space") - - if (H5FD_set_eoa(raw_file, H5FD_MEM_DRAW, (addr + size)) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "can't modify EOA") - - if (H5FDread(raw_file, H5FD_MEM_DRAW, H5P_DEFAULT, addr, size, buf) < 0) - HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't read history header from file") - - if (H5FD_onion_history_header_decode(buf, hdr_out) == 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "can't decode history header") - - sum = H5_checksum_fletcher32(buf, size - 4); - if (hdr_out->checksum != sum) - HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "checksum mismatch between buffer and stored") - -done: - H5MM_xfree(buf); - - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD__onion_ingest_history_header() */ - -/*----------------------------------------------------------------------------- - * Read and decode the revision_record information from `raw_file` at - * `addr` .. `addr + size` (taken from whole-history), and store the decoded - * information in the structure at `r_out`. - *----------------------------------------------------------------------------- - */ -static herr_t -H5FD__onion_ingest_revision_record(H5FD_onion_revision_record_t *r_out, H5FD_t *raw_file, - const H5FD_onion_whole_history_t *whs, uint64_t revision_num) -{ - unsigned char *buf = NULL; - herr_t ret_value = SUCCEED; - uint64_t n = 0; - uint64_t high = 0; - uint64_t low = 0; - uint64_t range = 0; - uint32_t sum = 0; - haddr_t addr = 0; - haddr_t size = 0; - - FUNC_ENTER_PACKAGE; - - HDassert(r_out); - HDassert(raw_file); - HDassert(whs); - HDassert(whs->record_pointer_list); - HDassert(whs->n_revisions > 0); - - high = whs->n_revisions - 1; - range = high; - addr = (haddr_t)whs->record_pointer_list[high].phys_addr; - size = (haddr_t)whs->record_pointer_list[high].record_size; - - /* Initialize r_out - * - * TODO: This function should completely initialize r_out. Relying on - * other code to some of the work while we just paste over parts - * of the struct here is completely bananas. - */ - r_out->comment = H5MM_xfree(r_out->comment); - r_out->archival_index.list = H5MM_xfree(r_out->archival_index.list); - - if (H5FD_get_eof(raw_file, H5FD_MEM_DRAW) < (addr + size)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "at least one record extends beyond EOF") - - /* recovery-open may have EOA below revision record */ - if ((H5FD_get_eoa(raw_file, H5FD_MEM_DRAW) < (addr + size)) && - (H5FD_set_eoa(raw_file, H5FD_MEM_DRAW, (addr + size)) < 0)) { - HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "can't modify EOA"); - } - - /* Perform binary search on records to find target revision by ID. - * As IDs are added sequentially, they are "guaranteed" to be sorted. - */ - while (range > 0) { - n = (range / 2) + low; - addr = (haddr_t)whs->record_pointer_list[n].phys_addr; - size = (haddr_t)whs->record_pointer_list[n].record_size; - - if (NULL == (buf = H5MM_malloc(sizeof(char) * size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer space") - - if (H5FDread(raw_file, H5FD_MEM_DRAW, H5P_DEFAULT, addr, size, buf) < 0) - HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't read revision record from file") - - if (H5FD_onion_revision_record_decode(buf, r_out) != size) - HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "can't decode revision record (initial)") - - sum = H5_checksum_fletcher32(buf, size - 4); - if (r_out->checksum != sum) - HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "checksum mismatch between buffer and stored") - - if (revision_num == r_out->revision_num) - break; - - H5MM_xfree(buf); - buf = NULL; - - r_out->archival_index.n_entries = 0; - r_out->comment_size = 0; - - if (r_out->revision_num < revision_num) - low = (n == high) ? high : n + 1; - else - high = (n == low) ? low : n - 1; - range = high - low; - } /* end while 'non-leaf' binary search */ - - if (range == 0) { - n = low; - addr = (haddr_t)whs->record_pointer_list[n].phys_addr; - size = (haddr_t)whs->record_pointer_list[n].record_size; - - if (NULL == (buf = H5MM_malloc(sizeof(char) * size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer space") - - if (H5FDread(raw_file, H5FD_MEM_DRAW, H5P_DEFAULT, addr, size, buf) < 0) - HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't read revision record from file") - - if (H5FD_onion_revision_record_decode(buf, r_out) != size) - HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "can't decode revision record (initial)") - - sum = H5_checksum_fletcher32(buf, size - 4); - if (r_out->checksum != sum) - HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "checksum mismatch between buffer and stored") - - if (revision_num != r_out->revision_num) - HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, - "could not find target revision!") /* TODO: corrupted? */ - } /* end if revision ID at 'leaf' in binary search */ - - if (r_out->comment_size > 0) - if (NULL == (r_out->comment = H5MM_malloc(sizeof(char) * r_out->comment_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate comment space") - - if (r_out->archival_index.n_entries > 0) - if (NULL == (r_out->archival_index.list = - H5MM_calloc(r_out->archival_index.n_entries * sizeof(H5FD_onion_index_entry_t)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate index entry list") - - if (H5FD_onion_revision_record_decode(buf, r_out) != size) - HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "can't decode revision record (final)") - -done: - H5MM_xfree(buf); - if (ret_value == FAIL) { - H5MM_xfree(r_out->comment); - H5MM_xfree(r_out->archival_index.list); - } - - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD__onion_ingest_revision_record() */ - -/*----------------------------------------------------------------------------- - * Read and decode the whole-history information from `raw_file` at - * `addr` .. `addr + size` (taken from history header), and store the decoded - * information in the structure at `whs_out`. - * - * If successful, `whs_out->record_pointer_list` is always allocated, even if - * there is zero revisions. - *----------------------------------------------------------------------------- - */ -static herr_t -H5FD__onion_ingest_whole_history(H5FD_onion_whole_history_t *whs_out, H5FD_t *raw_file, haddr_t addr, - haddr_t size) -{ - unsigned char *buf = NULL; - herr_t ret_value = SUCCEED; - uint32_t sum = 0; - - FUNC_ENTER_PACKAGE; - - if (H5FD_get_eof(raw_file, H5FD_MEM_DRAW) < (addr + size)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "header indicates whole-history beyond EOF") - - buf = H5MM_malloc(sizeof(char) * size); - if (NULL == buf) { - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer space"); - } - - if (H5FD_set_eoa(raw_file, H5FD_MEM_DRAW, (addr + size)) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "can't modify EOA") - - if (H5FDread(raw_file, H5FD_MEM_DRAW, H5P_DEFAULT, addr, size, buf) < 0) - HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't read whole-history from file") - - if (H5FD_onion_whole_history_decode(buf, whs_out) != size) - HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "can't decode whole-history (initial)") - - sum = H5_checksum_fletcher32(buf, size - 4); - if (whs_out->checksum != sum) - HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "checksum mismatch between buffer and stored") - - whs_out->record_pointer_list = H5MM_calloc(whs_out->n_revisions * sizeof(H5FD_onion_record_pointer_t)); - if (whs_out->n_revisions > 0 && NULL == whs_out->record_pointer_list) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate record pointer list") - - if (H5FD_onion_whole_history_decode(buf, whs_out) != size) - HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "can't decode whole-history (final)") - -done: - H5MM_xfree(buf); - if (ret_value == FAIL) - H5MM_xfree(whs_out->record_pointer_list); - - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD__onion_ingest_whole_history() */ - -/*----------------------------------------------------------------------------- * Function: H5FD__onion_open * * Purpose: Open an onionized file @@ -1809,7 +839,7 @@ H5FD__onion_open(const char *filename, unsigned flags, hid_t fapl_id, haddr_t ma file->header.version = H5FD__ONION_HEADER_VERSION_CURR; file->header.page_size = file->fa.page_size; /* guarded on FAPL-set */ - file->summary.version = H5FD__ONION_WHOLE_HISTORY_VERSION_CURR; + file->history.version = H5FD__ONION_WHOLE_HISTORY_VERSION_CURR; file->rev_record.version = H5FD__ONION_REVISION_RECORD_VERSION_CURR; file->rev_record.archival_index.version = H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR; @@ -1864,9 +894,9 @@ H5FD__onion_open(const char *filename, unsigned flags, hid_t fapl_id, haddr_t ma /* TODO: Move to a new function */ if (NULL == file->backing_onion) { if (H5F_ACC_RDWR & flags) { - H5FD_onion_history_header_t * hdr_p = NULL; - H5FD_onion_whole_history_t * whs_p = NULL; - H5FD_onion_revision_record_t *rec_p = NULL; + H5FD_onion_history_header_t * hdr = NULL; + H5FD_onion_history_t * history = NULL; + H5FD_onion_revision_record_t *rec = NULL; unsigned char * head_buf = NULL; unsigned char * wh_buf = NULL; uint64_t size = 0; @@ -1874,16 +904,16 @@ H5FD__onion_open(const char *filename, unsigned flags, hid_t fapl_id, haddr_t ma HDassert(file != NULL); - hdr_p = &file->header; - whs_p = &file->summary; - rec_p = &file->rev_record; + hdr = &file->header; + history = &file->history; + rec = &file->rev_record; new_open = true; if (H5FD_ONION_FAPL_INFO_CREATE_FLAG_ENABLE_DIVERGENT_HISTORY & file->fa.creation_flags) - hdr_p->flags |= H5FD__ONION_HEADER_FLAG_DIVERGENT_HISTORY; + hdr->flags |= H5FD__ONION_HEADER_FLAG_DIVERGENT_HISTORY; if (H5FD_ONION_FAPL_INFO_CREATE_FLAG_ENABLE_PAGE_ALIGNMENT & file->fa.creation_flags) { - hdr_p->flags |= H5FD__ONION_HEADER_FLAG_PAGE_ALIGNMENT; + hdr->flags |= H5FD__ONION_HEADER_FLAG_PAGE_ALIGNMENT; file->page_align_history = TRUE; } @@ -1892,8 +922,8 @@ H5FD__onion_open(const char *filename, unsigned flags, hid_t fapl_id, haddr_t ma } if (H5FD_set_eoa(file->backing_canon, H5FD_MEM_DRAW, canon_eof) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTSET, NULL, "can't extend EOA") - hdr_p->origin_eof = canon_eof; - file->logi_eof = canon_eof; + hdr->origin_eof = canon_eof; + file->logi_eof = canon_eof; backing_fapl_id = H5FD__onion_get_legit_fapl_id(file->fa.backing_fapl_id); if (H5I_INVALID_HID == backing_fapl_id) @@ -1907,54 +937,50 @@ H5FD__onion_open(const char *filename, unsigned flags, hid_t fapl_id, haddr_t ma HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "cannot open the backing onion file") } - /* Write history header with "no" whole-history summary to history */ - hdr_p->whole_history_size = H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY; /* record for later use */ - hdr_p->whole_history_addr = + /* Write history header with "no" history */ + hdr->history_size = H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY; /* record for later use */ + hdr->history_addr = H5FD__ONION_ENCODED_SIZE_HEADER + 1; /* TODO: comment these 2 or do some other way */ head_buf = H5MM_malloc(H5FD__ONION_ENCODED_SIZE_HEADER); if (NULL == head_buf) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't allocate buffer") - size = H5FD_onion_history_header_encode(hdr_p, head_buf, &hdr_p->checksum); + size = H5FD__onion_history_header_encode(hdr, head_buf, &hdr->checksum); if (H5FD__ONION_ENCODED_SIZE_HEADER != size) HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "can't encode history header") - /* must use public API to correctly set DXPL context :( */ wh_buf = H5MM_malloc(H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY); if (NULL == wh_buf) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't allocate buffer") - saved_size = size; - whs_p->n_revisions = 0; - size = H5FD_onion_whole_history_encode(whs_p, wh_buf, &whs_p->checksum); - file->header.whole_history_size = size; /* record for later use */ + saved_size = size; + history->n_revisions = 0; + size = H5FD__onion_history_encode(history, wh_buf, &history->checksum); + file->header.history_size = size; /* record for later use */ if (H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY != size) { - HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "can't encode whole-history") + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "can't encode history") } if (H5FD_set_eoa(file->backing_onion, H5FD_MEM_DRAW, saved_size + size + 1) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTSET, NULL, "can't extend EOA") - /* must use public API to correctly set DXPL context :( */ - if (H5FDwrite(file->backing_onion, H5FD_MEM_DRAW, H5P_DEFAULT, 0, saved_size, head_buf) < 0) { + if (H5FD_write(file->backing_onion, H5FD_MEM_DRAW, 0, saved_size, head_buf) < 0) { HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, NULL, "cannot write header to the backing onion file") } file->history_eof = (haddr_t)saved_size; if (TRUE == file->page_align_history) - file->history_eof = - (file->history_eof + (hdr_p->page_size - 1)) & (~(hdr_p->page_size - 1)); + file->history_eof = (file->history_eof + (hdr->page_size - 1)) & (~(hdr->page_size - 1)); - rec_p->archival_index.list = NULL; + rec->archival_index.list = NULL; - file->header.whole_history_addr = file->history_eof; + file->header.history_addr = file->history_eof; - /* Write nascent whole-history summary (with no revisions) to the backing onion file */ - if (H5FDwrite(file->backing_onion, H5FD_MEM_DRAW, H5P_DEFAULT, saved_size + 1, size, wh_buf) < - 0) { + /* Write nascent history (with no revisions) to the backing onion file */ + if (H5FD_write(file->backing_onion, H5FD_MEM_DRAW, saved_size + 1, size, wh_buf) < 0) { HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, NULL, - "cannot write summary to the backing onion file") + "cannot write history to the backing onion file") } - file->header.whole_history_size = size; /* record for later use */ + file->header.history_size = size; /* record for later use */ H5MM_xfree(head_buf); H5MM_xfree(wh_buf); @@ -1982,23 +1008,22 @@ H5FD__onion_open(const char *filename, unsigned flags, hid_t fapl_id, haddr_t ma } else { /* Read in the history from the onion file */ - if (H5FD__onion_ingest_whole_history(&file->summary, file->backing_onion, - file->header.whole_history_addr, - file->header.whole_history_size) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, NULL, "can't get whole-history from backing store") + if (H5FD__onion_ingest_history(&file->history, file->backing_onion, file->header.history_addr, + file->header.history_size) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, NULL, "can't get history from backing store") /* Sanity check on revision ID */ - if (fa->revision_num > file->summary.n_revisions && + if (fa->revision_num > file->history.n_revisions && fa->revision_num != H5FD_ONION_FAPL_INFO_REVISION_ID_LATEST) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "target revision ID out of range") if (fa->revision_num == 0) { file->rev_record.logi_eof = canon_eof; } - else if (file->summary.n_revisions > 0 && + else if (file->history.n_revisions > 0 && H5FD__onion_ingest_revision_record( - &file->rev_record, file->backing_onion, &file->summary, - MIN(fa->revision_num - 1, (file->summary.n_revisions - 1))) < 0) { + &file->rev_record, file->backing_onion, &file->history, + MIN(fa->revision_num - 1, (file->history.n_revisions - 1))) < 0) { HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, NULL, "can't get revision record from backing store") } @@ -2050,10 +1075,10 @@ done: HDONE_ERROR(H5E_VFL, H5E_CANTRELEASE, NULL, "can't destroy backing recov") if (file->rev_index) - if (H5FD_onion_revision_index_destroy(file->rev_index) < 0) + if (H5FD__onion_revision_index_destroy(file->rev_index) < 0) HDONE_ERROR(H5E_VFL, H5E_CANTRELEASE, NULL, "can't destroy revision index") - H5MM_xfree(file->summary.record_pointer_list); + H5MM_xfree(file->history.record_locs); H5MM_xfree(file->name_recov); H5MM_xfree(file->rev_record.comment); @@ -2094,16 +1119,16 @@ H5FD__onion_open_rw(H5FD_onion_t *file, unsigned int flags, haddr_t maxaddr, boo if (file->header.flags & H5FD__ONION_HEADER_FLAG_WRITE_LOCK) HGOTO_ERROR(H5E_VFL, H5E_UNSUPPORTED, FAIL, "can't write-open write-locked file") - /* Copy whole-history to recovery file */ + /* Copy history to recovery file */ if (NULL == (file->backing_recov = H5FD_open(file->name_recov, (flags | H5F_ACC_CREAT | H5F_ACC_TRUNC), file->fa.backing_fapl_id, maxaddr))) HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, FAIL, "unable to create recovery file") - if (0 == (size = H5FD__onion_whole_history_write(&file->summary, file->backing_recov, 0, 0))) - HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "can't write whole-history to recovery file") - if (size != file->header.whole_history_size) - HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "written whole-history differed from expected size") + if (0 == (size = H5FD__onion_write_history(&file->history, file->backing_recov, 0, 0))) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "can't write history to recovery file") + if (size != file->header.history_size) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "written history differed from expected size") /* Set write-lock flag in onion header */ @@ -2112,15 +1137,15 @@ H5FD__onion_open_rw(H5FD_onion_t *file, unsigned int flags, haddr_t maxaddr, boo file->header.flags |= H5FD__ONION_HEADER_FLAG_WRITE_LOCK; - if (0 == (size = H5FD_onion_history_header_encode(&file->header, buf, &_sum))) + if (0 == (size = H5FD__onion_history_header_encode(&file->header, buf, &_sum))) HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "problem encoding history header") - if (H5FDwrite(file->backing_onion, H5FD_MEM_DRAW, H5P_DEFAULT, 0, (haddr_t)size, buf) < 0) + if (H5FD_write(file->backing_onion, H5FD_MEM_DRAW, 0, (haddr_t)size, buf) < 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "can't write updated history header") /* Prepare revision index and finalize write-mode open */ - if (NULL == (file->rev_index = H5FD_onion_revision_index_init(file->fa.page_size))) + if (NULL == (file->rev_index = H5FD__onion_revision_index_init(file->fa.page_size))) HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't initialize revision index") file->rev_record.parent_revision_num = file->rev_record.revision_num; if (!new_open) @@ -2136,7 +1161,7 @@ done: } if (file->rev_index != NULL) { - if (H5FD_onion_revision_index_destroy(file->rev_index) < 0) + if (H5FD__onion_revision_index_destroy(file->rev_index) < 0) HDONE_ERROR(H5E_VFL, H5E_CANTRELEASE, FAIL, "can't destroy revision index") file->rev_index = NULL; } @@ -2164,8 +1189,6 @@ H5FD__onion_read(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, h size_t n_pages = 0; uint32_t page_size = 0; uint32_t page_size_log2 = 0; - size_t i = 0; - size_t j = 0; size_t bytes_to_read = len; unsigned char *buf_out = (unsigned char *)_buf_out; herr_t ret_value = SUCCEED; @@ -2187,8 +1210,8 @@ H5FD__onion_read(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, h n_pages = (len + page_size - 1) >> page_size_log2; /* Read, page-by-page */ - for (i = 0; i < n_pages; i++) { - const H5FD_onion_index_entry_t *entry_out_p = NULL; + for (size_t i = 0; i < n_pages; i++) { + const H5FD_onion_index_entry_t *entry_out = NULL; haddr_t page_gap_head = 0; /* start of page to start of buffer */ haddr_t page_gap_tail = 0; /* end of buffer to end of page */ size_t page_readsize = 0; @@ -2209,15 +1232,15 @@ H5FD__onion_read(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, h page_readsize = (size_t)page_size - page_gap_head - page_gap_tail; if (TRUE == file->is_open_rw && file->fa.revision_num != 0 && - H5FD_onion_revision_index_find(file->rev_index, page_i, &entry_out_p)) { - if (H5FDread(file->backing_onion, H5FD_MEM_DRAW, H5P_DEFAULT, - (haddr_t)entry_out_p->phys_addr + page_gap_head, page_readsize, buf_out) < 0) + H5FD__onion_revision_index_find(file->rev_index, page_i, &entry_out)) { + if (H5FD_read(file->backing_onion, H5FD_MEM_DRAW, entry_out->phys_addr + page_gap_head, + page_readsize, buf_out) < 0) HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't get working file data") } /* end if page exists in 'live' revision index */ else if (file->fa.revision_num != 0 && - H5FD_onion_archival_index_find(&file->rev_record.archival_index, page_i, &entry_out_p)) { - if (H5FDread(file->backing_onion, H5FD_MEM_DRAW, H5P_DEFAULT, - (haddr_t)entry_out_p->phys_addr + page_gap_head, page_readsize, buf_out) < 0) + H5FD__onion_archival_index_find(&file->rev_record.archival_index, page_i, &entry_out)) { + if (H5FD_read(file->backing_onion, H5FD_MEM_DRAW, entry_out->phys_addr + page_gap_head, + page_readsize, buf_out) < 0) HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't get previously-amended file data") } /* end if page exists in 'dead' archival index */ else { @@ -2227,15 +1250,14 @@ H5FD__onion_read(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, h haddr_t read_size = MIN(overlap_size, page_readsize); /* Get all original bytes in page range */ - if ((read_size > 0) && - H5FDread(file->backing_canon, type, H5P_DEFAULT, addr_start, read_size, buf_out) < 0) { + if ((read_size > 0) && H5FD_read(file->backing_canon, type, addr_start, read_size, buf_out) < 0) { HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't get original file data") } /* Fill with 0s any gaps after end of original bytes * and before end of page. */ - for (j = read_size; j < page_readsize; j++) + for (size_t j = read_size; j < page_readsize; j++) buf_out[j] = 0; } /* end if page exists in neither index */ @@ -2250,13 +1272,11 @@ done: } /* end H5FD__onion_read() */ /*----------------------------------------------------------------------------- - * * Function: H5FD__onion_set_eoa * * Purpose: Set end-of-address marker of the logical file. * * Return: SUCCEED/FAIL - * *----------------------------------------------------------------------------- */ static herr_t @@ -2289,8 +1309,6 @@ H5FD__onion_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, unsigned char * page_buf = NULL; uint32_t page_size = 0; uint32_t page_size_log2 = 0; - size_t i = 0; - size_t j = 0; size_t bytes_to_write = len; const unsigned char *buf = (const unsigned char *)_buf; herr_t ret_value = SUCCEED; @@ -2317,10 +1335,10 @@ H5FD__onion_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "cannot allocate temporary buffer") /* Write, page-by-page */ - for (i = 0; i < n_pages; i++) { + for (size_t i = 0; i < n_pages; i++) { const unsigned char * write_buf = buf; H5FD_onion_index_entry_t new_entry; - const H5FD_onion_index_entry_t *entry_out_p = NULL; + const H5FD_onion_index_entry_t *entry_out = NULL; haddr_t page_gap_head = 0; /* start of page to start of buffer */ haddr_t page_gap_tail = 0; /* end of buffer to end of page */ size_t page_n_used = 0; /* nbytes from buffer for this page-write */ @@ -2342,19 +1360,19 @@ H5FD__onion_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, page_n_used = page_size - page_gap_head - page_gap_tail; /* Modify page in revision index, if present */ - if (H5FD_onion_revision_index_find(file->rev_index, page_i, &entry_out_p)) { + if (H5FD__onion_revision_index_find(file->rev_index, page_i, &entry_out)) { if (page_gap_head | page_gap_tail) { /* Copy existing page verbatim. */ - if (H5FDread(file->backing_onion, H5FD_MEM_DRAW, H5P_DEFAULT, (haddr_t)entry_out_p->phys_addr, - page_size, page_buf) < 0) + if (H5FD_read(file->backing_onion, H5FD_MEM_DRAW, entry_out->phys_addr, page_size, page_buf) < + 0) HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't get working file data") /* Overlay delta from input buffer onto page buffer. */ HDmemcpy(page_buf + page_gap_head, buf, page_n_used); write_buf = page_buf; } /* end if partial page */ - if (H5FDwrite(file->backing_onion, H5FD_MEM_DRAW, H5P_DEFAULT, (haddr_t)entry_out_p->phys_addr, - page_size, write_buf) < 0) + if (H5FD_write(file->backing_onion, H5FD_MEM_DRAW, entry_out->phys_addr, page_size, write_buf) < + 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "write amended page data to backing file") buf += page_n_used; /* overflow never touched */ @@ -2365,10 +1383,10 @@ H5FD__onion_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, if (page_gap_head || page_gap_tail) { /* Fill gaps with existing data or zeroes. */ - if (H5FD_onion_archival_index_find(&file->rev_record.archival_index, page_i, &entry_out_p)) { + if (H5FD__onion_archival_index_find(&file->rev_record.archival_index, page_i, &entry_out)) { /* Copy existing page verbatim. */ - if (H5FDread(file->backing_onion, H5FD_MEM_DRAW, H5P_DEFAULT, (haddr_t)entry_out_p->phys_addr, - page_size, page_buf) < 0) + if (H5FD_read(file->backing_onion, H5FD_MEM_DRAW, entry_out->phys_addr, page_size, page_buf) < + 0) HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't get previously-amended data") } /* end if page exists in 'dead' archival index */ else { @@ -2378,20 +1396,20 @@ H5FD__onion_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, /* Get all original bytes in page range */ if ((read_size > 0) && - H5FDread(file->backing_canon, type, H5P_DEFAULT, addr_start, read_size, page_buf) < 0) { + H5FD_read(file->backing_canon, type, addr_start, read_size, page_buf) < 0) { HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't get original file data") } /* Fill with 0s any gaps after end of original bytes * or start of page and before start of new data. */ - for (j = read_size; j < page_gap_head; j++) + for (size_t j = read_size; j < page_gap_head; j++) page_buf[j] = 0; /* Fill with 0s any gaps after end of original bytes * or end of new data and before end of page. */ - for (j = MAX(read_size, page_size - page_gap_tail); j < page_size; j++) + for (size_t j = MAX(read_size, page_size - page_gap_tail); j < page_size; j++) page_buf[j] = 0; } /* end if page exists in neither index */ @@ -2408,11 +1426,10 @@ H5FD__onion_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, if (H5FD_set_eoa(file->backing_onion, H5FD_MEM_DRAW, file->history_eof + page_size) < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "can't modify EOA for new page amendment") - if (H5FDwrite(file->backing_onion, H5FD_MEM_DRAW, H5P_DEFAULT, file->history_eof, page_size, - write_buf) < 0) + if (H5FD_write(file->backing_onion, H5FD_MEM_DRAW, file->history_eof, page_size, write_buf) < 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "write amended page data to backing file") - if (H5FD_onion_revision_index_insert(file->rev_index, &new_entry) < 0) + if (H5FD__onion_revision_index_insert(file->rev_index, &new_entry) < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTINSERT, FAIL, "can't insert new index entry into revision index") file->history_eof += page_size; @@ -2465,7 +1482,7 @@ H5FD__onion_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void H5_A if (!output || !*output) HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL, "the output parameter is null") - **((uint64_t **)output) = file->summary.n_revisions; + **((uint64_t **)output) = file->history.n_revisions; break; /* Unknown op code */ default: @@ -2478,515 +1495,112 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__onion_ctl() */ -/*----------------------------------------------------------------------------- - * Function: H5FD_onion_archival_index_is_valid - * - * Purpose: Determine whether an archival index structure is valid. - * - * + Verify page size (power of two). - * + Verify list exists. - * + Verify list contents: - * + Sorted by increasing logical address (no duplicates) - * + Logical addresses are multiples of page size. - * - * Return: TRUE/FALSE - *----------------------------------------------------------------------------- - */ -hbool_t -H5FD_onion_archival_index_is_valid(const H5FD_onion_archival_index_t *aix) -{ - hbool_t ret_value = TRUE; - - FUNC_ENTER_NOAPI_NOINIT_NOERR; - - HDassert(aix); - - if (H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR != aix->version) - HGOTO_DONE(FALSE) - if (NULL == aix->list) - HGOTO_DONE(FALSE) - - /* Ensure list is sorted on logi_page field */ - if (aix->n_entries > 1) - for (uint64_t i = 1; i < aix->n_entries - 1; i++) - if (aix->list[i + 1].logi_page <= aix->list[i].logi_page) - HGOTO_DONE(FALSE) - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD_onion_archival_index_is_valid() */ - -/*----------------------------------------------------------------------------- - * Function: H5FD_onion_archival_index_find - * - * Purpose: Retrieve the archival index entry by logical page ID. - * - * The archival index pointer must point to a valid index entry. - * The entry out pointer-pointer cannot be null. - * - * Return: Success: Positive value (1) -- entry found. - * Entry out pointer-pointer is set to point to entry. - * Failure: Zero (0) -- entry not found. - * Entry out pointer-pointer is unmodified. - *----------------------------------------------------------------------------- - */ -int -H5FD_onion_archival_index_find(const H5FD_onion_archival_index_t *aix, uint64_t logi_page, - const H5FD_onion_index_entry_t **entry_out_p) -{ - uint64_t low = 0; - uint64_t high = 0; - uint64_t n = 0; - uint64_t range = 0; - H5FD_onion_index_entry_t *x = NULL; - int ret_value = 0; - - FUNC_ENTER_NOAPI_NOINIT_NOERR; - - HDassert(aix); - HDassert(H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR == aix->version); - HDassert(entry_out_p); - if (aix->n_entries != 0) - HDassert(aix->list); - - high = aix->n_entries - 1; - range = high; - - /* Trivial cases */ - if (aix->n_entries == 0 || logi_page > aix->list[high].logi_page || logi_page < aix->list[0].logi_page) - HGOTO_DONE(0) - - /* - * Binary search on sorted list - */ - - /* Winnow down to first of found or one element */ - while (range > 0) { - HDassert(high < aix->n_entries); - n = low + (range / 2); - x = &(aix->list[n]); - if (x->logi_page == logi_page) { - *entry_out_p = x; /* element found at fence */ - ret_value = 1; - goto done; - } - else if (x->logi_page < logi_page) { - low = (n == high) ? high : n + 1; - } - else { - high = (n == low) ? low : n - 1; - } - range = high - low; - } - - HDassert(high == low); /* one element */ - - /* n == low/high check because we may have tested it already above */ - if ((n != low || n != high) && (aix->list[low].logi_page == logi_page)) { - *entry_out_p = &aix->list[low]; - ret_value = 1; - } - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD_onion_archival_index_find() */ - -/*----------------------------------------------------------------------------- - * Function: H5FD_onion_revision_index_destroy +/*------------------------------------------------------------------------- + * Function: H5FDget_onion_revision_count * - * Purpose: Release all resources of a revision index. + * Purpose: Get the number of revisions in an onion file * * Return: SUCCEED/FAIL - *----------------------------------------------------------------------------- + *------------------------------------------------------------------------- */ herr_t -H5FD_onion_revision_index_destroy(H5FD__onion_revision_index_t *rix) -{ - size_t i = 0; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NOINIT_NOERR; - - HDassert(rix); - HDassert(H5FD__ONION_REVISION_INDEX_VERSION_CURR == rix->version); - - for (i = 0; 0 < rix->_hash_table_n_keys_populated && i < rix->_hash_table_size; i++) { - H5FD_onion_revision_index_hash_chain_node_t *next_p = NULL; - H5FD_onion_revision_index_hash_chain_node_t *node_p = rix->_hash_table[i]; - - if (node_p != NULL) - rix->_hash_table_n_keys_populated -= 1; - - while (node_p != NULL) { - HDassert(H5FD__ONION_REVISION_INDEX_HASH_CHAIN_NODE_VERSION_CURR == node_p->version); - - next_p = node_p->next; - H5MM_xfree(node_p); - node_p = next_p; - } - } - H5MM_xfree(rix->_hash_table); - H5MM_xfree(rix); - - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD_onion_revision_index_destroy() */ - -/*----------------------------------------------------------------------------- - * Function: H5FD_onion_revision_index_init - * - * Purpose: Initialize a revision index structure with a default starting - * size. A new structure is allocated and populated with initial - * values. - * - * Return: Success: Pointer to newly-allocated structure - * Failure: NULL - *----------------------------------------------------------------------------- - */ -H5FD__onion_revision_index_t * -H5FD_onion_revision_index_init(uint32_t page_size) +H5FDonion_get_revision_count(const char *filename, hid_t fapl_id, size_t *revision_count /*out*/) { - uint64_t table_size = U64_EXP2(H5FD__ONION_REVISION_INDEX_STARTING_SIZE_LOG2); - H5FD__onion_revision_index_t *rix = NULL; - H5FD__onion_revision_index_t *ret_value = NULL; - - FUNC_ENTER_NOAPI_NOINIT; + H5P_genplist_t *plist = NULL; + H5FD_t * file = NULL; + herr_t ret_value = SUCCEED; - HDassert(0 != page_size); - HDassert(POWER_OF_TWO(page_size)); + FUNC_ENTER_API(FAIL) + H5TRACE3("e", "*six", filename, fapl_id, revision_count); - if (NULL == (rix = H5MM_calloc(sizeof(H5FD__onion_revision_index_t)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "cannot allocate index") + /* Check args */ + if (!filename || !HDstrcmp(filename, "")) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid file name") + if (!revision_count) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "revision count can't be null") - if (NULL == - (rix->_hash_table = H5MM_calloc(table_size * sizeof(H5FD_onion_revision_index_hash_chain_node_t *)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "cannot allocate hash table") + /* Make sure using the correct driver */ + if (NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid FAPL ID") + if (H5FD_ONION != H5P_peek_driver(plist)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a Onion VFL driver") - rix->version = H5FD__ONION_REVISION_INDEX_VERSION_CURR; - rix->n_entries = 0; - /* Compute and store log2(page_size) */ - for (rix->page_size_log2 = 0; (((uint32_t)1 << rix->page_size_log2) & page_size) == 0; - rix->page_size_log2++) - ; - rix->_hash_table_size = table_size; - rix->_hash_table_size_log2 = H5FD__ONION_REVISION_INDEX_STARTING_SIZE_LOG2; - rix->_hash_table_n_keys_populated = 0; + /* Open the file with the driver */ + if (NULL == (file = H5FD_open(filename, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF))) + HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, FAIL, "unable to open file with onion driver") - ret_value = rix; + /* Call the private function */ + if (H5FD__get_onion_revision_count(file, revision_count) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "failed to get the number of revisions") done: - if (NULL == ret_value) - H5MM_xfree(rix); + /* Close H5FD_t structure pointer */ + if (file && H5FD_close(file) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, "unable to close file") - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD_onion_revision_index_init() */ + FUNC_LEAVE_API(ret_value) +} -/*----------------------------------------------------------------------------- - * Function: H5FD__onion_revision_index_resize() - * - * Purpose: Replace the hash table in the revision index. - * - * Doubles the available number of keys, re-hashes table contents, - * and updates relevant components in the index structure. +/*------------------------------------------------------------------------- + * Function: H5FD__get_onion_revision_count * - * Fails if unable to allocate space for larger hash table. + * Purpose: Private version of H5FDget_onion_revision_count() * * Return: SUCCEED/FAIL - *----------------------------------------------------------------------------- + *------------------------------------------------------------------------- */ static herr_t -H5FD__onion_revision_index_resize(H5FD__onion_revision_index_t *rix) -{ - H5FD_onion_revision_index_hash_chain_node_t **new_table = NULL; - uint64_t i = 0; - uint64_t new_size_log2 = rix->_hash_table_size_log2 + 1; - uint64_t new_size = U64_EXP2(new_size_log2); - uint64_t new_n_keys_populated = 0; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_PACKAGE; - - HDassert(rix); - HDassert(H5FD__ONION_REVISION_INDEX_VERSION_CURR == rix->version); - HDassert(rix->_hash_table); - - if (NULL == (new_table = H5MM_calloc(new_size * sizeof(H5FD_onion_revision_index_hash_chain_node_t *)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "cannot allocate new hash table") - - for (i = 0; i < rix->_hash_table_size; i++) { - while (rix->_hash_table[i] != NULL) { - H5FD_onion_revision_index_hash_chain_node_t *node = NULL; - uint64_t key = 0; - - /* Pop entry off of bucket stack and re-hash */ - node = rix->_hash_table[i]; - rix->_hash_table[i] = node->next; - node->next = NULL; - key = node->entry_data.logi_page & (new_size - 1); - - if (NULL == new_table[key]) { - new_table[key] = node; - new_n_keys_populated++; - } - else { - node->next = new_table[i]; - new_table[i] = node; - } - } - } - - H5MM_xfree(rix->_hash_table); - rix->_hash_table_size = new_size; - rix->_hash_table_size_log2 = new_size_log2; - rix->_hash_table_n_keys_populated = new_n_keys_populated; - rix->_hash_table = new_table; - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD__onion_revision_index_resize() */ - -/*----------------------------------------------------------------------------- - * Function: H5FD_onion_revision_index_insert() - * - * Purpose: Add an entry to the revision index, or update an existing - * entry. Must be used to update entries as well as add -- - * checksum value will change. - * - * Entry data is copied into separate memory region; user pointer - * can be safley re-used or discarded after operation. - * - * Return: SUCCEED/FAIL - *----------------------------------------------------------------------------- - */ -herr_t -H5FD_onion_revision_index_insert(H5FD__onion_revision_index_t *rix, const H5FD_onion_index_entry_t *entry) +H5FD__get_onion_revision_count(H5FD_t *file, size_t *revision_count) { - uint64_t key = 0; - H5FD_onion_revision_index_hash_chain_node_t * node = NULL; - H5FD_onion_revision_index_hash_chain_node_t **append_dest = NULL; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NOINIT; - - HDassert(rix); - HDassert(H5FD__ONION_REVISION_INDEX_VERSION_CURR == rix->version); - HDassert(entry); - - /* Resize and re-hash table if necessary */ - if (rix->n_entries >= (rix->_hash_table_size * 2) || - rix->_hash_table_n_keys_populated >= (rix->_hash_table_size / 2)) { - if (H5FD__onion_revision_index_resize(rix) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_NONE_MINOR, FAIL, "unable to resize and hash table") - } - - key = entry->logi_page & (rix->_hash_table_size - 1); - HDassert(key < rix->_hash_table_size); + uint64_t op_code; + uint64_t flags; + herr_t ret_value = SUCCEED; - if (NULL == rix->_hash_table[key]) { - /* Key maps to empty bucket */ + FUNC_ENTER_PACKAGE - append_dest = &rix->_hash_table[key]; - rix->_hash_table_n_keys_populated++; - } - else { - /* Key maps to populated bucket */ + HDassert(file); + HDassert(revision_count); - for (node = rix->_hash_table[key]; node != NULL; node = node->next) { - append_dest = &node->next; /* look for bucket tail */ - if (entry->logi_page == node->entry_data.logi_page) { - if (entry->phys_addr != node->entry_data.phys_addr) { - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "physical address mismatch"); - } - HDmemcpy(&node->entry_data, entry, sizeof(H5FD_onion_index_entry_t)); - append_dest = NULL; /* Node updated, do not append */ - break; - } - } - } + op_code = H5FD_CTL__GET_NUM_REVISIONS; + flags = H5FD_CTL__FAIL_IF_UNKNOWN_FLAG; - /* Add new entry to bucket chain */ - if (append_dest != NULL) { - if (NULL == (node = H5MM_malloc(sizeof(H5FD_onion_revision_index_hash_chain_node_t)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "cannot allocate new ash chain node") - node->version = H5FD__ONION_REVISION_INDEX_HASH_CHAIN_NODE_VERSION_CURR; - node->next = NULL; - HDmemcpy(&node->entry_data, entry, sizeof(H5FD_onion_index_entry_t)); - *append_dest = node; - rix->n_entries++; - } + /* Get the number of revisions via the ctl callback */ + if (H5FD_ctl(file, op_code, flags, NULL, (void **)&revision_count) < 0) + HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL, "VFD ctl request failed") done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD_onion_revision_index_insert() */ - -/*----------------------------------------------------------------------------- - * Function: H5FD_onion_revision_index_find() - * - * - * Purpose: Get pointer to revision index entry with the given page number, - * if it exists in the index. - * - * Return: Success: Positive value (1) -- entry found. - * Entry out pointer-pointer is set to point to entry. - * Failure: Zero (0) -- entry not found. - * Entry out pointer-pointer is unmodified. - *----------------------------------------------------------------------------- - */ -int -H5FD_onion_revision_index_find(const H5FD__onion_revision_index_t *rix_p, uint64_t logi_page, - const H5FD_onion_index_entry_t **entry_out_p) -{ - uint64_t key = 0; - int ret_value = 0; - - FUNC_ENTER_NOAPI_NOINIT_NOERR; - - HDassert(rix_p); - HDassert(H5FD__ONION_REVISION_INDEX_VERSION_CURR == rix_p->version); - HDassert(rix_p->_hash_table); - HDassert(entry_out_p); - - key = logi_page & (rix_p->_hash_table_size - 1); - HDassert(key < rix_p->_hash_table_size); - - if (rix_p->_hash_table[key] != NULL) { - H5FD_onion_revision_index_hash_chain_node_t *node = NULL; - - for (node = rix_p->_hash_table[key]; node != NULL; node = node->next) { - if (logi_page == node->entry_data.logi_page) { - *entry_out_p = &node->entry_data; - ret_value = 1; - break; - } - } - } - - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD_onion_revision_index_find() */ - -/*----------------------------------------------------------------------------- - * Callback for comparisons in sorting archival index entries by logi_page. - *----------------------------------------------------------------------------- - */ -static int -H5FD__onion_archival_index_list_sort_cmp(const void *_a, const void *_b) -{ - const H5FD_onion_index_entry_t *a = (const H5FD_onion_index_entry_t *)_a; - const H5FD_onion_index_entry_t *b = (const H5FD_onion_index_entry_t *)_b; - - if (a->logi_page < b->logi_page) - return -1; - else if (a->logi_page > b->logi_page) - return 1; - return 0; -} /* end H5FD__onion_archival_index_list_sort_cmp() */ + FUNC_LEAVE_NOAPI(ret_value) +} /*----------------------------------------------------------------------------- - * Function: H5FD_onion_merge_revision_index_into_archival_index - * - * Purpose: Merge index entries from revision index into archival index. + * Function: H5FD__onion_write_final_history * - * If successful, the archival index is expanded 'behind the - * scenes' and new entries from the revision index are inserted. - * The archival index remains sorted in ascending order of logical - * address. - * - * The conversion to archival index changes logical pages in - * revision index entries to their logical addresses in-file. + * Purpose: Write final history to appropriate backing file on file close * * Return: SUCCEED/FAIL *----------------------------------------------------------------------------- */ herr_t -H5FD_onion_merge_revision_index_into_archival_index(const H5FD__onion_revision_index_t *rix, - H5FD_onion_archival_index_t * aix) +H5FD__onion_write_final_history(H5FD_onion_t *file) { - uint64_t i = 0; - uint64_t n_kept = 0; - H5FD_onion_index_entry_t * kept_list = NULL; - H5FD_onion_archival_index_t new_aix = { - H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR, 0, /* page_size_log2 tbd */ - 0, /* n_entries */ - NULL, /* list pointer (allocated later) */ - }; + size_t size = 0; herr_t ret_value = SUCCEED; - FUNC_ENTER_NOAPI_NOINIT; - - HDassert(rix); - HDassert(aix); - HDassert(H5FD__ONION_REVISION_INDEX_VERSION_CURR == rix->version); - HDassert(H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR == aix->version); - HDassert(aix->page_size_log2 == rix->page_size_log2); - - /* If the revision index is empty there is nothing to archive */ - if (rix->n_entries == 0) - goto done; - - /* Add all revision index entries to new archival list */ - new_aix.page_size_log2 = aix->page_size_log2; - - if (NULL == (new_aix.list = H5MM_calloc(rix->n_entries * sizeof(H5FD_onion_index_entry_t)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate new archival index list") - - for (i = 0; i < rix->_hash_table_size; i++) { - const H5FD_onion_revision_index_hash_chain_node_t *node_p = NULL; - - for (node_p = rix->_hash_table[i]; node_p != NULL; node_p = node_p->next) { - HDmemcpy(&new_aix.list[new_aix.n_entries], &node_p->entry_data, sizeof(H5FD_onion_index_entry_t)); - new_aix.n_entries++; - } - } - - /* Sort the new archival list */ - HDqsort(new_aix.list, new_aix.n_entries, sizeof(H5FD_onion_index_entry_t), - H5FD__onion_archival_index_list_sort_cmp); + FUNC_ENTER_PACKAGE; - /* Add the old archival index entries to a 'kept' list containing the - * old archival list entries that are not also included in the revision - * list. - * - * Note that kept_list will be NULL if there are no entries in the passed-in - * archival list. - */ - if (aix->n_entries > 0) - if (NULL == (kept_list = H5MM_calloc(aix->n_entries * sizeof(H5FD_onion_index_entry_t)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate larger archival index list") + /* TODO: history EOF may not be correct (under what circumstances?) */ + if (0 == (size = H5FD__onion_write_history(&(file->history), file->backing_onion, file->history_eof, + file->history_eof))) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "can't write final history") - for (i = 0; i < aix->n_entries; i++) { - const H5FD_onion_index_entry_t *_p = NULL; + if (size != file->header.history_size) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "written history differed from expected size") - /* Add only if page not already added from revision index */ - if (H5FD_onion_archival_index_find(&new_aix, aix->list[i].logi_page, &_p) == 0) { - HDmemcpy(&kept_list[n_kept], &aix->list[i], sizeof(H5FD_onion_index_entry_t)); - n_kept++; - } - } - - /* Destroy the old archival list and replace with a list big enough to hold - * the revision list entries and the kept list entries + /* Is last write operation to history file; no need to extend to page + * boundary if set to page-align. */ - H5MM_xfree(aix->list); - if (NULL == (aix->list = H5MM_calloc((new_aix.n_entries + n_kept) * sizeof(H5FD_onion_index_entry_t)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate exact-size archival index list") - - /* Copy (new) revision list entries to replacement list */ - HDmemcpy(aix->list, new_aix.list, sizeof(H5FD_onion_index_entry_t) * new_aix.n_entries); - aix->n_entries = new_aix.n_entries; - - /* Copy (old) kept archival list entries to replacement list */ - if (n_kept > 0) { - HDmemcpy(&aix->list[aix->n_entries], kept_list, sizeof(H5FD_onion_index_entry_t) * n_kept); - aix->n_entries += n_kept; - } - - /* Sort this list */ - HDqsort(aix->list, aix->n_entries, sizeof(H5FD_onion_index_entry_t), - H5FD__onion_archival_index_list_sort_cmp); + file->history_eof += size; done: - /* Free the temporary lists */ - H5MM_xfree(kept_list); - H5MM_xfree(new_aix.list); - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FD_onion_merge_revision_index_into_entry_list() */ +} /* end H5FD__onion_write_final_history() */ diff --git a/src/H5FDonion_history.c b/src/H5FDonion_history.c new file mode 100644 index 0000000..39acbb1 --- /dev/null +++ b/src/H5FDonion_history.c @@ -0,0 +1,480 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Onion Virtual File Driver (VFD) + * + * Purpose: Code for the onion file's history + */ + +/* This source code file is part of the H5FD driver module */ +#include "H5FDdrvr_module.h" + +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5FDprivate.h" /* File drivers */ +#include "H5FDonion.h" /* Onion file driver */ +#include "H5FDonion_priv.h" /* Onion file driver internals */ + +/*----------------------------------------------------------------------------- + * Function: H5FD_ingest_history_header + * + * Purpose: Read and decode the history header information from `raw_file` + * at `addr`, and store the decoded information in the structure + * at `hdr_out`. + * + * Return: SUCCEED/FAIL + *----------------------------------------------------------------------------- + */ +herr_t +H5FD__onion_ingest_history_header(H5FD_onion_history_header_t *hdr_out, H5FD_t *raw_file, haddr_t addr) +{ + unsigned char *buf = NULL; + herr_t ret_value = SUCCEED; + haddr_t size = (haddr_t)H5FD__ONION_ENCODED_SIZE_HEADER; + uint32_t sum = 0; + + FUNC_ENTER_PACKAGE; + + if (H5FD_get_eof(raw_file, H5FD_MEM_DRAW) < (addr + size)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "header indicates history beyond EOF") + + if (NULL == (buf = H5MM_malloc(sizeof(char) * size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer space") + + if (H5FD_set_eoa(raw_file, H5FD_MEM_DRAW, (addr + size)) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "can't modify EOA") + + if (H5FD_read(raw_file, H5FD_MEM_DRAW, addr, size, buf) < 0) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't read history header from file") + + if (H5FD__onion_history_header_decode(buf, hdr_out) == 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "can't decode history header") + + sum = H5_checksum_fletcher32(buf, size - 4); + if (hdr_out->checksum != sum) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "checksum mismatch between buffer and stored") + +done: + H5MM_xfree(buf); + + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_ingest_history_header() */ + +/*----------------------------------------------------------------------------- + * Read and decode the history information from `raw_file` at + * `addr` .. `addr + size` (taken from history header), and store the decoded + * information in the structure at `history_out`. + * + * If successful, `history_out->record_locs` is always allocated, even if + * there is zero revisions. + *----------------------------------------------------------------------------- + */ +herr_t +H5FD__onion_ingest_history(H5FD_onion_history_t *history_out, H5FD_t *raw_file, haddr_t addr, haddr_t size) +{ + unsigned char *buf = NULL; + herr_t ret_value = SUCCEED; + uint32_t sum = 0; + + FUNC_ENTER_PACKAGE; + + if (H5FD_get_eof(raw_file, H5FD_MEM_DRAW) < (addr + size)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "header indicates history beyond EOF") + + if (NULL == (buf = H5MM_malloc(sizeof(char) * size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer space"); + + if (H5FD_set_eoa(raw_file, H5FD_MEM_DRAW, (addr + size)) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "can't modify EOA") + + if (H5FD_read(raw_file, H5FD_MEM_DRAW, addr, size, buf) < 0) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't read history from file") + + if (H5FD__onion_history_decode(buf, history_out) != size) + HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "can't decode history (initial)") + + sum = H5_checksum_fletcher32(buf, size - 4); + if (history_out->checksum != sum) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "checksum mismatch between buffer and stored") + + history_out->record_locs = H5MM_calloc(history_out->n_revisions * sizeof(H5FD_onion_record_loc_t)); + if (history_out->n_revisions > 0 && NULL == history_out->record_locs) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate record pointer list") + + if (H5FD__onion_history_decode(buf, history_out) != size) + HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "can't decode history (final)") + +done: + H5MM_xfree(buf); + if (ret_value == FAIL) + H5MM_xfree(history_out->record_locs); + + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_ingest_history() */ + +/*------------------------------------------------------------------------- + * Function: H5FD__onion_write_header + * + * Purpose: Write in-memory history header to appropriate backing file. + * Overwrites existing header data. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +herr_t +H5FD__onion_write_header(H5FD_onion_history_header_t *header, H5FD_t *backing_file) +{ + uint32_t sum = 0; /* Not used, but required by the encoder */ + uint64_t size = 0; + unsigned char *buf = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE; + + if (NULL == (buf = H5MM_malloc(H5FD__ONION_ENCODED_SIZE_HEADER))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "can't allocate buffer for updated history header") + + if (0 == (size = H5FD__onion_history_header_encode(header, buf, &sum))) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "problem encoding updated history header") + + if (H5FD_write(backing_file, H5FD_MEM_DRAW, 0, (haddr_t)size, buf) < 0) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "can't write updated history header") + +done: + H5MM_xfree(buf); + + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_write_header()*/ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_write_history + * + * Purpose: Encode and write history to file at the given address. + * + * Returns: Success: Number of bytes written to destination file (always non-zero) + * Failure: 0 + *----------------------------------------------------------------------------- + */ +uint64_t +H5FD__onion_write_history(H5FD_onion_history_t *history, H5FD_t *file_dest, haddr_t off_start, + haddr_t filesize_curr) +{ + uint32_t _sum = 0; /* Required by the API call but unused here */ + uint64_t size = 0; + unsigned char *buf = NULL; + uint64_t ret_value = 0; + + FUNC_ENTER_PACKAGE; + + if (NULL == (buf = H5MM_malloc(H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY + + (H5FD__ONION_ENCODED_SIZE_RECORD_POINTER * history->n_revisions)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, 0, "can't allocate buffer for updated history") + + if (0 == (size = H5FD__onion_history_encode(history, buf, &_sum))) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, 0, "problem encoding updated history") + + if ((size + off_start > filesize_curr) && (H5FD_set_eoa(file_dest, H5FD_MEM_DRAW, off_start + size) < 0)) + HGOTO_ERROR(H5E_VFL, H5E_CANTSET, 0, "can't modify EOA for updated history") + + if (H5FD_write(file_dest, H5FD_MEM_DRAW, off_start, size, buf) < 0) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, 0, "can't write history as intended") + + ret_value = size; + +done: + H5MM_xfree(buf); + + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_write_history() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_history_header_decode + * + * Purpose: Attempt to read a buffer and store it as a history-header + * structure. + * + * Implementation must correspond with + * H5FD__onion_history_header_encode(). + * + * Return: Success: Number of bytes read from buffer + * Failure: 0 + *----------------------------------------------------------------------------- + */ +uint64_t +H5FD__onion_history_header_decode(unsigned char *buf, H5FD_onion_history_header_t *header) +{ + uint32_t ui32 = 0; + uint32_t sum = 0; + uint64_t ui64 = 0; + uint8_t * ui8p = NULL; + unsigned char *ptr = NULL; + uint64_t ret_value = 0; + + FUNC_ENTER_PACKAGE; + + HDassert(buf != NULL); + HDassert(header != NULL); + HDassert(H5FD__ONION_HEADER_VERSION_CURR == header->version); + + if (HDstrncmp((const char *)buf, H5FD__ONION_HEADER_SIGNATURE, 4)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid header signature") + + if (buf[4] != H5FD__ONION_HEADER_VERSION_CURR) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid header version") + + ptr = buf + 5; + ui32 = 0; + HDmemcpy(&ui32, ptr, 3); + ui8p = (uint8_t *)&ui32; + UINT32DECODE(ui8p, header->flags); + ptr += 3; + + HDmemcpy(&ui32, ptr, 4); + ui8p = (uint8_t *)&ui32; + UINT32DECODE(ui8p, header->page_size); + ptr += 4; + + HDmemcpy(&ui64, ptr, 8); + ui8p = (uint8_t *)&ui64; + UINT32DECODE(ui8p, header->origin_eof); + ptr += 8; + + HDmemcpy(&ui64, ptr, 8); + ui8p = (uint8_t *)&ui64; + UINT32DECODE(ui8p, header->history_addr); + ptr += 8; + + HDmemcpy(&ui64, ptr, 8); + ui8p = (uint8_t *)&ui64; + UINT32DECODE(ui8p, header->history_size); + ptr += 8; + + sum = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); + + HDmemcpy(&ui32, ptr, 4); + ui8p = (uint8_t *)&ui32; + UINT32DECODE(ui8p, header->checksum); + ptr += 4; + + if (sum != header->checksum) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "checksum mismatch") + + ret_value = (uint64_t)(ptr - buf); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_history_header_decode() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_history_header_encode + * + * Purpose: Write history-header structure to the given buffer. + * All multi-byte elements are stored in little-endian word order. + * + * Implementation must correspond with + * H5FD__onion_history_header_decode(). + * + * The destination buffer must be sufficiently large to hold the + * encoded contents (H5FD__ONION_ENCODED_SIZE_HEADER). + * + * Return: Number of bytes written to buffer. + * The checksum of the generated buffer contents (excluding the + * checksum itself) is stored in the pointer `sum_out`). + *----------------------------------------------------------------------------- + */ +uint64_t +H5FD__onion_history_header_encode(H5FD_onion_history_header_t *header, unsigned char *buf, uint32_t *sum_out) +{ + unsigned char *ptr = buf; + uint64_t ret_value = 0; + + FUNC_ENTER_PACKAGE_NOERR; + + HDassert(buf != NULL); + HDassert(sum_out != NULL); + HDassert(header != NULL); + HDassert(H5FD__ONION_HEADER_VERSION_CURR == header->version); + HDassert(0 == (header->flags & 0xFF000000)); /* max three bits long */ + + HDmemcpy(ptr, H5FD__ONION_HEADER_SIGNATURE, 4); + ptr += 4; + HDmemcpy(ptr, (unsigned char *)&header->version, 1); + ptr += 1; + UINT32ENCODE(ptr, header->flags); + ptr -= 1; /* truncate to three bytes */ + UINT32ENCODE(ptr, header->page_size); + UINT64ENCODE(ptr, header->origin_eof); + UINT64ENCODE(ptr, header->history_addr); + UINT64ENCODE(ptr, header->history_size); + *sum_out = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); + UINT32ENCODE(ptr, *sum_out); + ret_value = (uint64_t)(ptr - buf); + + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_history_header_encode() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_history_decode + * + * Purpose: Attempt to read a buffer and store it as a history + * structure. + * + * Implementation must correspond with + * H5FD__onion_history_encode(). + * + * MUST BE CALLED TWICE: + * On the first call, n_records in the destination structure must + * be zero, and record_locs be NULL. + * + * If the buffer is well-formed, the destination structure is + * tentatively populated with fixed-size values, and the number of + * bytes read are returned. + * + * Prior to the second call, the user must allocate space for + * record_locs to hold n_records record-pointer structs. + * + * Then the decode operation is called a second time, and all + * components will be populated (and again number of bytes read is + * returned). + * + * Return: Success: Number of bytes read from buffer + * Failure: 0 + *----------------------------------------------------------------------------- + */ +uint64_t +H5FD__onion_history_decode(unsigned char *buf, H5FD_onion_history_t *history) +{ + uint32_t ui32 = 0; + uint32_t sum = 0; + uint64_t ui64 = 0; + uint64_t n_revisions = 0; + uint8_t * ui8p = NULL; + unsigned char *ptr = NULL; + uint64_t ret_value = 0; + + FUNC_ENTER_PACKAGE; + + HDassert(buf != NULL); + HDassert(history != NULL); + HDassert(H5FD__ONION_WHOLE_HISTORY_VERSION_CURR == history->version); + + if (HDstrncmp((const char *)buf, "OWHS", 4)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid signature") + + if (H5FD__ONION_WHOLE_HISTORY_VERSION_CURR != buf[4]) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid version") + + ptr = buf + 8; + + HDmemcpy(&ui64, ptr, 8); + ui8p = (uint8_t *)&ui64; + UINT64DECODE(ui8p, n_revisions); + ptr += 8; + + if (0 == history->n_revisions) { + history->n_revisions = n_revisions; + ptr += H5FD__ONION_ENCODED_SIZE_RECORD_POINTER * n_revisions; + } + else { + if (history->n_revisions != n_revisions) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, + "history argument suggests different revision count than encoded buffer") + if (NULL == history->record_locs) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "list is NULL -- cannot populate") + + for (uint64_t i = 0; i < n_revisions; i++) { + H5FD_onion_record_loc_t *rloc = &history->record_locs[i]; + + HDmemcpy(&ui64, ptr, 8); + ui8p = (uint8_t *)&ui64; + UINT64DECODE(ui8p, rloc->phys_addr); + ptr += 8; + + HDmemcpy(&ui64, ptr, 8); + ui8p = (uint8_t *)&ui64; + UINT64DECODE(ui8p, rloc->record_size); + ptr += 8; + + HDmemcpy(&ui32, ptr, 4); + ui8p = (uint8_t *)&ui32; + UINT64DECODE(ui8p, rloc->checksum); + ptr += 4; + } + } + + sum = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); + + HDmemcpy(&ui32, ptr, 4); + ui8p = (uint8_t *)&ui32; + UINT32DECODE(ui8p, history->checksum); + ptr += 4; + + if (sum != history->checksum) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "checksum mismatch") + + ret_value = (uint64_t)(ptr - buf); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_history_decode() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_history_encode + * + * Purpose: Write history structure to the given buffer. + * All multi-byte elements are stored in little-endian word order. + * + * Implementation must correspond with + * H5FD__onion_history_decode(). + * + * The destination buffer must be sufficiently large to hold the + * encoded contents. + * (Hint: `sizeof(history struct) + + * sizeof(record-pointer-struct) * n_records)` guarantees + * ample/excess space.) + * + * Return: Number of bytes written to buffer. + * The checksum of the generated buffer contents (excluding the + * checksum itself) is stored in the pointer `sum_out`). + *----------------------------------------------------------------------------- + */ +uint64_t +H5FD__onion_history_encode(H5FD_onion_history_t *history, unsigned char *buf, uint32_t *sum_out) +{ + unsigned char *ptr = buf; + uint32_t vers_u32 = (uint32_t)history->version; /* pad out unused bytes */ + + FUNC_ENTER_PACKAGE_NOERR; + + HDassert(history != NULL); + HDassert(H5FD__ONION_WHOLE_HISTORY_VERSION_CURR == history->version); + HDassert(buf != NULL); + HDassert(sum_out != NULL); + + HDmemcpy(ptr, H5FD__ONION_WHOLE_HISTORY_SIGNATURE, 4); + ptr += 4; + UINT32ENCODE(ptr, vers_u32); + UINT64ENCODE(ptr, history->n_revisions); + if (history->n_revisions > 0) { + HDassert(history->record_locs != NULL); /* TODO: error? */ + for (uint64_t i = 0; i < history->n_revisions; i++) { + UINT64ENCODE(ptr, history->record_locs[i].phys_addr); + UINT64ENCODE(ptr, history->record_locs[i].record_size); + UINT32ENCODE(ptr, history->record_locs[i].checksum); + } + } + *sum_out = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); + UINT32ENCODE(ptr, *sum_out); + + FUNC_LEAVE_NOAPI((uint64_t)(ptr - buf)); +} /* end H5FD__onion_history_encode() */ diff --git a/src/H5FDonion_history.h b/src/H5FDonion_history.h new file mode 100644 index 0000000..e9034a2 --- /dev/null +++ b/src/H5FDonion_history.h @@ -0,0 +1,88 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Onion Virtual File Driver (VFD) + * + * Purpose: Interface for the onion file's history + */ + +#ifndef H5FDonion_history_H +#define H5FDonion_history_H + +/* Number of bytes to encode fixed-size components */ +#define H5FD__ONION_ENCODED_SIZE_HEADER 40 +#define H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY 20 + +/* Flags must align exactly one per bit, up to 24 bits */ +#define H5FD__ONION_HEADER_FLAG_WRITE_LOCK 0x1 +#define H5FD__ONION_HEADER_FLAG_DIVERGENT_HISTORY 0x2 +#define H5FD__ONION_HEADER_FLAG_PAGE_ALIGNMENT 0x4 +#define H5FD__ONION_HEADER_SIGNATURE "OHDH" +#define H5FD__ONION_HEADER_VERSION_CURR 1 + +#define H5FD__ONION_WHOLE_HISTORY_SIGNATURE "OWHS" +#define H5FD__ONION_WHOLE_HISTORY_VERSION_CURR 1 + +/* In-memory representation of the on-store onion history file header. + */ +typedef struct H5FD_onion_history_header_t { + uint8_t version; + uint32_t flags; /* At most three bytes used! */ + uint32_t page_size; + uint64_t origin_eof; /* Size of the 'original' canonical file */ + uint64_t history_addr; + uint64_t history_size; + uint32_t checksum; +} H5FD_onion_history_header_t; + +/* In-memory representation of the on-store revision record. + * Used in the history. + */ +typedef struct H5FD_onion_record_loc_t { + haddr_t phys_addr; + size_t record_size; + uint32_t checksum; +} H5FD_onion_record_loc_t; + +/* In-memory representation of the on-store history record/summary. + */ +typedef struct H5FD_onion_history_t { + uint8_t version; + uint64_t n_revisions; + H5FD_onion_record_loc_t *record_locs; + uint32_t checksum; +} H5FD_onion_history_t; + +#ifdef __cplusplus +extern "C" { +#endif +H5_DLL herr_t H5FD__onion_ingest_history_header(H5FD_onion_history_header_t *hdr_out, H5FD_t *raw_file, + haddr_t addr); +H5_DLL herr_t H5FD__onion_ingest_history(H5FD_onion_history_t *history_out, H5FD_t *raw_file, haddr_t addr, + haddr_t size); + +H5_DLL herr_t H5FD__onion_write_header(H5FD_onion_history_header_t *header, H5FD_t *backing_file); +H5_DLL uint64_t H5FD__onion_write_history(H5FD_onion_history_t *history, H5FD_t *backing_file, + haddr_t off_start, haddr_t filesize_curr); + +H5_DLL uint64_t H5FD__onion_history_header_decode(unsigned char *, H5FD_onion_history_header_t *); +H5_DLL uint64_t H5FD__onion_history_header_encode(H5FD_onion_history_header_t *, unsigned char *, uint32_t *); + +H5_DLL uint64_t H5FD__onion_history_decode(unsigned char *, H5FD_onion_history_t *); +H5_DLL uint64_t H5FD__onion_history_encode(H5FD_onion_history_t *, unsigned char *, uint32_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* H5FDonion_history_H */ diff --git a/src/H5FDonion_index.c b/src/H5FDonion_index.c new file mode 100644 index 0000000..66af1a1 --- /dev/null +++ b/src/H5FDonion_index.c @@ -0,0 +1,934 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Onion Virtual File Driver (VFD) + * + * Purpose: Code for the archival and revision indexes + */ + +/* This source code file is part of the H5FD driver module */ +#include "H5FDdrvr_module.h" + +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5FDprivate.h" /* File drivers */ +#include "H5FDonion.h" /* Onion file driver */ +#include "H5FDonion_priv.h" /* Onion file driver internals */ + +/* 2^n for uint64_t types -- H5_EXP2 unsafe past 32 bits */ +#define U64_EXP2(n) ((uint64_t)1 << (n)) + +static int H5FD__onion_archival_index_list_sort_cmp(const void *, const void *); +static herr_t H5FD__onion_revision_index_resize(H5FD_onion_revision_index_t *rix); + +/*----------------------------------------------------------------------------- + * Read and decode the revision_record information from `raw_file` at + * `addr` .. `addr + size` (taken from history), and store the decoded + * information in the structure at `r_out`. + *----------------------------------------------------------------------------- + */ +herr_t +H5FD__onion_ingest_revision_record(H5FD_onion_revision_record_t *r_out, H5FD_t *raw_file, + const H5FD_onion_history_t *history, uint64_t revision_num) +{ + unsigned char *buf = NULL; + herr_t ret_value = SUCCEED; + uint64_t n = 0; + uint64_t high = 0; + uint64_t low = 0; + uint64_t range = 0; + uint32_t sum = 0; + haddr_t addr = 0; + size_t size = 0; + + FUNC_ENTER_PACKAGE; + + HDassert(r_out); + HDassert(raw_file); + HDassert(history); + HDassert(history->record_locs); + HDassert(history->n_revisions > 0); + + high = history->n_revisions - 1; + range = high; + addr = history->record_locs[high].phys_addr; + size = history->record_locs[high].record_size; + + /* Initialize r_out + * + * TODO: This function should completely initialize r_out. Relying on + * other code to some of the work while we just paste over parts + * of the struct here is completely bananas. + */ + r_out->comment = H5MM_xfree(r_out->comment); + r_out->archival_index.list = H5MM_xfree(r_out->archival_index.list); + + if (H5FD_get_eof(raw_file, H5FD_MEM_DRAW) < (addr + size)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "at least one record extends beyond EOF") + + /* recovery-open may have EOA below revision record */ + if ((H5FD_get_eoa(raw_file, H5FD_MEM_DRAW) < (addr + size)) && + (H5FD_set_eoa(raw_file, H5FD_MEM_DRAW, (addr + size)) < 0)) { + HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "can't modify EOA"); + } + + /* Perform binary search on records to find target revision by ID. + * As IDs are added sequentially, they are "guaranteed" to be sorted. + */ + while (range > 0) { + n = (range / 2) + low; + addr = history->record_locs[n].phys_addr; + size = history->record_locs[n].record_size; + + if (NULL == (buf = H5MM_malloc(sizeof(char) * size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer space") + + if (H5FD_read(raw_file, H5FD_MEM_DRAW, addr, size, buf) < 0) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't read revision record from file") + + if (H5FD__onion_revision_record_decode(buf, r_out) != size) + HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "can't decode revision record (initial)") + + sum = H5_checksum_fletcher32(buf, size - 4); + if (r_out->checksum != sum) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "checksum mismatch between buffer and stored") + + if (revision_num == r_out->revision_num) + break; + + H5MM_xfree(buf); + buf = NULL; + + r_out->archival_index.n_entries = 0; + r_out->comment_size = 0; + + if (r_out->revision_num < revision_num) + low = (n == high) ? high : n + 1; + else + high = (n == low) ? low : n - 1; + range = high - low; + } /* end while 'non-leaf' binary search */ + + if (range == 0) { + n = low; + addr = history->record_locs[n].phys_addr; + size = history->record_locs[n].record_size; + + if (NULL == (buf = H5MM_malloc(sizeof(char) * size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate buffer space") + + if (H5FD_read(raw_file, H5FD_MEM_DRAW, addr, size, buf) < 0) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "can't read revision record from file") + + if (H5FD__onion_revision_record_decode(buf, r_out) != size) + HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "can't decode revision record (initial)") + + sum = H5_checksum_fletcher32(buf, size - 4); + if (r_out->checksum != sum) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "checksum mismatch between buffer and stored") + + if (revision_num != r_out->revision_num) + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, + "could not find target revision!") /* TODO: corrupted? */ + } /* end if revision ID at 'leaf' in binary search */ + + if (r_out->comment_size > 0) + if (NULL == (r_out->comment = H5MM_malloc(sizeof(char) * r_out->comment_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate comment space") + + if (r_out->archival_index.n_entries > 0) + if (NULL == (r_out->archival_index.list = + H5MM_calloc(r_out->archival_index.n_entries * sizeof(H5FD_onion_index_entry_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate index entry list") + + if (H5FD__onion_revision_record_decode(buf, r_out) != size) + HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "can't decode revision record (final)") + +done: + H5MM_xfree(buf); + if (ret_value == FAIL) { + H5MM_xfree(r_out->comment); + H5MM_xfree(r_out->archival_index.list); + } + + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_ingest_revision_record() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_archival_index_is_valid + * + * Purpose: Determine whether an archival index structure is valid. + * + * + Verify page size (power of two). + * + Verify list exists. + * + Verify list contents: + * + Sorted by increasing logical address (no duplicates) + * + Logical addresses are multiples of page size. + * + * Return: TRUE/FALSE + *----------------------------------------------------------------------------- + */ +hbool_t +H5FD__onion_archival_index_is_valid(const H5FD_onion_archival_index_t *aix) +{ + hbool_t ret_value = TRUE; + + FUNC_ENTER_PACKAGE_NOERR; + + HDassert(aix); + + if (H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR != aix->version) + HGOTO_DONE(FALSE) + if (NULL == aix->list) + HGOTO_DONE(FALSE) + + /* Ensure list is sorted on logi_page field */ + if (aix->n_entries > 1) + for (uint64_t i = 1; i < aix->n_entries - 1; i++) + if (aix->list[i + 1].logi_page <= aix->list[i].logi_page) + HGOTO_DONE(FALSE) + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_archival_index_is_valid() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_archival_index_find + * + * Purpose: Retrieve the archival index entry by logical page ID. + * + * The archival index pointer must point to a valid index entry. + * The entry out pointer-pointer cannot be null. + * + * Return: Success: Positive value (1) -- entry found. + * Entry out pointer-pointer is set to point to entry. + * Failure: Zero (0) -- entry not found. + * Entry out pointer-pointer is unmodified. + *----------------------------------------------------------------------------- + */ +int +H5FD__onion_archival_index_find(const H5FD_onion_archival_index_t *aix, uint64_t logi_page, + const H5FD_onion_index_entry_t **entry_out) +{ + uint64_t low = 0; + uint64_t high = 0; + uint64_t n = 0; + uint64_t range = 0; + H5FD_onion_index_entry_t *x = NULL; + int ret_value = 0; + + FUNC_ENTER_PACKAGE_NOERR; + + HDassert(aix); + HDassert(H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR == aix->version); + HDassert(entry_out); + if (aix->n_entries != 0) + HDassert(aix->list); + + high = aix->n_entries - 1; + range = high; + + /* Trivial cases */ + if (aix->n_entries == 0 || logi_page > aix->list[high].logi_page || logi_page < aix->list[0].logi_page) + HGOTO_DONE(0) + + /* + * Binary search on sorted list + */ + + /* Winnow down to first of found or one element */ + while (range > 0) { + HDassert(high < aix->n_entries); + n = low + (range / 2); + x = &(aix->list[n]); + if (x->logi_page == logi_page) { + *entry_out = x; /* element found at fence */ + ret_value = 1; + goto done; + } + else if (x->logi_page < logi_page) { + low = (n == high) ? high : n + 1; + } + else { + high = (n == low) ? low : n - 1; + } + range = high - low; + } + + HDassert(high == low); /* one element */ + + /* n == low/high check because we may have tested it already above */ + if ((n != low || n != high) && (aix->list[low].logi_page == logi_page)) { + *entry_out = &aix->list[low]; + ret_value = 1; + } + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_archival_index_find() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_revision_index_destroy + * + * Purpose: Release all resources of a revision index. + * + * Return: SUCCEED/FAIL + *----------------------------------------------------------------------------- + */ +herr_t +H5FD__onion_revision_index_destroy(H5FD_onion_revision_index_t *rix) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NOERR; + + HDassert(rix); + HDassert(H5FD__ONION_REVISION_INDEX_VERSION_CURR == rix->version); + + for (size_t i = 0; 0 < rix->_hash_table_n_keys_populated && i < rix->_hash_table_size; i++) { + H5FD_onion_revision_index_hash_chain_node_t *next = NULL; + H5FD_onion_revision_index_hash_chain_node_t *node = rix->_hash_table[i]; + + if (node != NULL) + rix->_hash_table_n_keys_populated -= 1; + + while (node != NULL) { + HDassert(H5FD__ONION_REVISION_INDEX_HASH_CHAIN_NODE_VERSION_CURR == node->version); + + next = node->next; + H5MM_xfree(node); + node = next; + } + } + H5MM_xfree(rix->_hash_table); + H5MM_xfree(rix); + + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_revision_index_destroy() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_revision_index_init + * + * Purpose: Initialize a revision index structure with a default starting + * size. A new structure is allocated and populated with initial + * values. + * + * Return: Success: Pointer to newly-allocated structure + * Failure: NULL + *----------------------------------------------------------------------------- + */ +H5FD_onion_revision_index_t * +H5FD__onion_revision_index_init(uint32_t page_size) +{ + uint64_t table_size = U64_EXP2(H5FD__ONION_REVISION_INDEX_STARTING_SIZE_LOG2); + H5FD_onion_revision_index_t *rix = NULL; + H5FD_onion_revision_index_t *ret_value = NULL; + + FUNC_ENTER_PACKAGE; + + HDassert(0 != page_size); + HDassert(POWER_OF_TWO(page_size)); + + if (NULL == (rix = H5MM_calloc(sizeof(H5FD_onion_revision_index_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "cannot allocate index") + + if (NULL == + (rix->_hash_table = H5MM_calloc(table_size * sizeof(H5FD_onion_revision_index_hash_chain_node_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "cannot allocate hash table") + + rix->version = H5FD__ONION_REVISION_INDEX_VERSION_CURR; + rix->n_entries = 0; + /* Compute and store log2(page_size) */ + for (rix->page_size_log2 = 0; (((uint32_t)1 << rix->page_size_log2) & page_size) == 0; + rix->page_size_log2++) + ; + rix->_hash_table_size = table_size; + rix->_hash_table_size_log2 = H5FD__ONION_REVISION_INDEX_STARTING_SIZE_LOG2; + rix->_hash_table_n_keys_populated = 0; + + ret_value = rix; + +done: + if (NULL == ret_value) + H5MM_xfree(rix); + + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_revision_index_init() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_revision_index_resize() + * + * Purpose: Replace the hash table in the revision index. + * + * Doubles the available number of keys, re-hashes table contents, + * and updates relevant components in the index structure. + * + * Fails if unable to allocate space for larger hash table. + * + * Return: SUCCEED/FAIL + *----------------------------------------------------------------------------- + */ +static herr_t +H5FD__onion_revision_index_resize(H5FD_onion_revision_index_t *rix) +{ + H5FD_onion_revision_index_hash_chain_node_t **new_table = NULL; + + uint64_t new_size_log2 = rix->_hash_table_size_log2 + 1; + uint64_t new_size = U64_EXP2(new_size_log2); + uint64_t new_n_keys_populated = 0; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE; + + HDassert(rix); + HDassert(H5FD__ONION_REVISION_INDEX_VERSION_CURR == rix->version); + HDassert(rix->_hash_table); + + if (NULL == (new_table = H5MM_calloc(new_size * sizeof(H5FD_onion_revision_index_hash_chain_node_t *)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "cannot allocate new hash table") + + for (uint64_t i = 0; i < rix->_hash_table_size; i++) { + while (rix->_hash_table[i] != NULL) { + H5FD_onion_revision_index_hash_chain_node_t *node = NULL; + uint64_t key = 0; + + /* Pop entry off of bucket stack and re-hash */ + node = rix->_hash_table[i]; + rix->_hash_table[i] = node->next; + node->next = NULL; + key = node->entry_data.logi_page & (new_size - 1); + + if (NULL == new_table[key]) { + new_table[key] = node; + new_n_keys_populated++; + } + else { + node->next = new_table[i]; + new_table[i] = node; + } + } + } + + H5MM_xfree(rix->_hash_table); + rix->_hash_table_size = new_size; + rix->_hash_table_size_log2 = new_size_log2; + rix->_hash_table_n_keys_populated = new_n_keys_populated; + rix->_hash_table = new_table; + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_revision_index_resize() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_revision_index_insert() + * + * Purpose: Add an entry to the revision index, or update an existing + * entry. Must be used to update entries as well as add -- + * checksum value will change. + * + * Entry data is copied into separate memory region; user pointer + * can be safley re-used or discarded after operation. + * + * Return: SUCCEED/FAIL + *----------------------------------------------------------------------------- + */ +herr_t +H5FD__onion_revision_index_insert(H5FD_onion_revision_index_t *rix, const H5FD_onion_index_entry_t *entry) +{ + uint64_t key = 0; + H5FD_onion_revision_index_hash_chain_node_t * node = NULL; + H5FD_onion_revision_index_hash_chain_node_t **append_dest = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE; + + HDassert(rix); + HDassert(H5FD__ONION_REVISION_INDEX_VERSION_CURR == rix->version); + HDassert(entry); + + /* Resize and re-hash table if necessary */ + if (rix->n_entries >= (rix->_hash_table_size * 2) || + rix->_hash_table_n_keys_populated >= (rix->_hash_table_size / 2)) { + if (H5FD__onion_revision_index_resize(rix) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NONE_MINOR, FAIL, "unable to resize and hash table") + } + + key = entry->logi_page & (rix->_hash_table_size - 1); + HDassert(key < rix->_hash_table_size); + + if (NULL == rix->_hash_table[key]) { + /* Key maps to empty bucket */ + + append_dest = &rix->_hash_table[key]; + rix->_hash_table_n_keys_populated++; + } + else { + /* Key maps to populated bucket */ + + for (node = rix->_hash_table[key]; node != NULL; node = node->next) { + append_dest = &node->next; /* look for bucket tail */ + if (entry->logi_page == node->entry_data.logi_page) { + if (entry->phys_addr != node->entry_data.phys_addr) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "physical address mismatch"); + } + HDmemcpy(&node->entry_data, entry, sizeof(H5FD_onion_index_entry_t)); + append_dest = NULL; /* Node updated, do not append */ + break; + } + } + } + + /* Add new entry to bucket chain */ + if (append_dest != NULL) { + if (NULL == (node = H5MM_malloc(sizeof(H5FD_onion_revision_index_hash_chain_node_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "cannot allocate new ash chain node") + node->version = H5FD__ONION_REVISION_INDEX_HASH_CHAIN_NODE_VERSION_CURR; + node->next = NULL; + HDmemcpy(&node->entry_data, entry, sizeof(H5FD_onion_index_entry_t)); + *append_dest = node; + rix->n_entries++; + } + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_revision_index_insert() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_revision_index_find() + * + * + * Purpose: Get pointer to revision index entry with the given page number, + * if it exists in the index. + * + * Return: Success: Positive value (1) -- entry found. + * Entry out pointer-pointer is set to point to entry. + * Failure: Zero (0) -- entry not found. + * Entry out pointer-pointer is unmodified. + *----------------------------------------------------------------------------- + */ +int +H5FD__onion_revision_index_find(const H5FD_onion_revision_index_t *rix, uint64_t logi_page, + const H5FD_onion_index_entry_t **entry_out) +{ + uint64_t key = 0; + int ret_value = 0; + + FUNC_ENTER_PACKAGE_NOERR; + + HDassert(rix); + HDassert(H5FD__ONION_REVISION_INDEX_VERSION_CURR == rix->version); + HDassert(rix->_hash_table); + HDassert(entry_out); + + key = logi_page & (rix->_hash_table_size - 1); + HDassert(key < rix->_hash_table_size); + + if (rix->_hash_table[key] != NULL) { + H5FD_onion_revision_index_hash_chain_node_t *node = NULL; + + for (node = rix->_hash_table[key]; node != NULL; node = node->next) { + if (logi_page == node->entry_data.logi_page) { + *entry_out = &node->entry_data; + ret_value = 1; + break; + } + } + } + + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_revision_index_find() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_revision_record_decode + * + * Purpose: Attempt to read a buffer and store it as a revision record + * structure. + * + * Implementation must correspond with + * H5FD__onion_revision_record_encode(). + * + * MUST BE CALLED TWICE: + * On the first call, n_entries and comment_size in the + * destination structure must all all be zero, and their + * respective variable-length components (index_entry_list, + * comment) must all be NULL. + * + * If the buffer is well-formed, the destination structure is + * tentatively populated with fixed-size values, and the number of + * bytes read are returned. + * + * Prior to the second call, the user must allocate space for the + * variable-length components, in accordance with the associated + * indicators (array of index-entry structures for + * index_entry_list, of size n_entries; character arrays for + * comment, allocated with the *_size number of bytes -- space + * for NULL-terminator is included in _size). + * + * Then the decode operation is called a second time, and all + * components will be populated (and again number of bytes read is + * returned). + * + * Return: Success: Number of bytes read from buffer + * Failure: 0 + *----------------------------------------------------------------------------- + */ +uint64_t +H5FD__onion_revision_record_decode(unsigned char *buf, H5FD_onion_revision_record_t *record) +{ + uint32_t ui32 = 0; + uint32_t page_size = 0; + uint32_t sum = 0; + uint64_t ui64 = 0; + uint64_t n_entries = 0; + uint32_t comment_size = 0; + uint8_t * ui8p = NULL; + unsigned char *ptr = NULL; + uint64_t ret_value = 0; + + FUNC_ENTER_PACKAGE; + + HDassert(buf != NULL); + HDassert(record != NULL); + HDassert(H5FD__ONION_REVISION_RECORD_VERSION_CURR == record->version); + HDassert(H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR == record->archival_index.version); + + if (HDstrncmp((const char *)buf, H5FD__ONION_REVISION_RECORD_SIGNATURE, 4)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid signature") + + if (H5FD__ONION_REVISION_RECORD_VERSION_CURR != buf[4]) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid record version") + + ptr = buf + 8; + + HDmemcpy(&ui64, ptr, 8); + ui8p = (uint8_t *)&ui64; + UINT64DECODE(ui8p, record->revision_num); + ptr += 8; + + HDmemcpy(&ui64, ptr, 8); + ui8p = (uint8_t *)&ui64; + UINT64DECODE(ui8p, record->parent_revision_num); + ptr += 8; + + HDmemcpy(record->time_of_creation, ptr, 16); + ptr += 16; + + HDmemcpy(&ui64, ptr, 8); + ui8p = (uint8_t *)&ui64; + UINT64DECODE(ui8p, record->logi_eof); + ptr += 8; + + HDmemcpy(&ui32, ptr, 4); + ui8p = (uint8_t *)&ui32; + UINT32DECODE(ui8p, page_size); + ptr += 4; + + if (page_size == 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "page size is zero") + if (!POWER_OF_TWO(page_size)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "page size not power of two") + + for (record->archival_index.page_size_log2 = 0; + (((uint32_t)1 << record->archival_index.page_size_log2) & page_size) == 0; + record->archival_index.page_size_log2++) + ; + + HDmemcpy(&ui64, ptr, 8); + ui8p = (uint8_t *)&ui64; + UINT64DECODE(ui8p, n_entries); + ptr += 8; + + HDmemcpy(&ui32, ptr, 4); + ui8p = (uint8_t *)&ui32; + UINT32DECODE(ui8p, comment_size); + ptr += 4; + + if (record->archival_index.n_entries == 0) { + record->archival_index.n_entries = n_entries; + ptr += H5FD__ONION_ENCODED_SIZE_INDEX_ENTRY * n_entries; + } + else if (n_entries != record->archival_index.n_entries) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "n_entries in archival index does not match decoded") + } + else { + H5FD_onion_index_entry_t *entry = NULL; + + if (record->archival_index.list == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "no archival index entry list") + + for (size_t i = 0; i < n_entries; i++) { + entry = &record->archival_index.list[i]; + + HDmemcpy(&ui64, ptr, 8); + ui8p = (uint8_t *)&ui64; + UINT64DECODE(ui8p, entry->logi_page); + ptr += 8; + + /* logi_page actually encoded as address; check and convert */ + if (entry->logi_page & (page_size - 1)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "logical address does not align with page size") + + entry->logi_page = entry->logi_page >> record->archival_index.page_size_log2; + + HDmemcpy(&ui64, ptr, 8); + ui8p = (uint8_t *)&ui64; + UINT64DECODE(ui8p, entry->phys_addr); + ptr += 8; + + HDmemcpy(&ui32, ptr, 4); + ui8p = (uint8_t *)&ui32; + UINT32DECODE(ui8p, sum); + ptr += 4; + + ui32 = H5_checksum_fletcher32((ptr - 20), 16); + if (ui32 != sum) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "index entry checksum mismatch") + } + } + + if (record->comment_size == 0) { + if (record->comment != NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "comment pointer prematurely allocated") + record->comment_size = comment_size; + } + else { + if (record->comment == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "no comment pointer") + HDmemcpy(record->comment, ptr, comment_size); + } + ptr += comment_size; + + sum = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); + + HDmemcpy(&ui32, ptr, 4); + ui8p = (uint8_t *)&ui32; + UINT32DECODE(ui8p, record->checksum); + ptr += 4; + + if (sum != record->checksum) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "checksum mismatch") + + ret_value = (uint64_t)(ptr - buf); + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_revision_record_decode() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_revision_record_encode + * + * Purpose: Write revision-record structure to the given buffer. + * All multi-byte elements are stored in little-endian word order. + * + * Implementation must correspond with + * H5FD__onion_revision_record_decode(). + * + * The destination buffer must be sufficiently large to hold the + * encoded contents. + * (Hint: `sizeof(revision-record-struct) + comment-size + + * sizeof(index-entry-struct) * n_entries)` + * guarantees ample/excess space.) + * + * Return: Number of bytes written to buffer. + * The checksum of the generated buffer contents (excluding the + * checksum itself) is stored in the pointer `sum_out`). + *----------------------------------------------------------------------------- + */ +uint64_t +H5FD__onion_revision_record_encode(H5FD_onion_revision_record_t *record, unsigned char *buf, + uint32_t *sum_out) +{ + unsigned char *ptr = buf; /* original pointer */ + uint32_t vers_u32 = (uint32_t)record->version; /* pad out unused bytes */ + uint32_t page_size = 0; + + FUNC_ENTER_PACKAGE_NOERR; + + HDassert(sum_out != NULL); + HDassert(buf != NULL); + HDassert(record != NULL); + HDassert(vers_u32 < 0x100); + HDassert(H5FD__ONION_REVISION_RECORD_VERSION_CURR == record->version); + HDassert(H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR == record->archival_index.version); + + page_size = (uint32_t)(1 << record->archival_index.page_size_log2); + + HDmemcpy(ptr, H5FD__ONION_REVISION_RECORD_SIGNATURE, 4); + ptr += 4; + UINT32ENCODE(ptr, vers_u32); + UINT64ENCODE(ptr, record->revision_num); + UINT64ENCODE(ptr, record->parent_revision_num); + HDmemcpy(ptr, record->time_of_creation, 16); + ptr += 16; + UINT64ENCODE(ptr, record->logi_eof); + UINT32ENCODE(ptr, page_size); + UINT64ENCODE(ptr, record->archival_index.n_entries); + UINT32ENCODE(ptr, record->comment_size); + + if (record->archival_index.n_entries > 0) { + uint64_t page_size_log2 = record->archival_index.page_size_log2; + + HDassert(record->archival_index.list != NULL); + for (uint64_t i = 0; i < record->archival_index.n_entries; i++) { + uint32_t sum = 0; + H5FD_onion_index_entry_t *entry = NULL; + uint64_t logi_addr = 0; + + entry = &record->archival_index.list[i]; + logi_addr = entry->logi_page << page_size_log2; + + UINT64ENCODE(ptr, logi_addr); + UINT64ENCODE(ptr, entry->phys_addr); + sum = H5_checksum_fletcher32((ptr - 16), 16); + UINT32ENCODE(ptr, sum); + } + } + + if (record->comment_size > 0) { + HDassert(record->comment != NULL && *record->comment != '\0'); + HDmemcpy(ptr, record->comment, record->comment_size); + ptr += record->comment_size; + } + + *sum_out = H5_checksum_fletcher32(buf, (size_t)(ptr - buf)); + UINT32ENCODE(ptr, *sum_out); + + FUNC_LEAVE_NOAPI((uint64_t)(ptr - buf)); +} /* end H5FD__onion_revision_record_encode() */ + +/*----------------------------------------------------------------------------- + * Callback for comparisons in sorting archival index entries by logi_page. + *----------------------------------------------------------------------------- + */ +static int +H5FD__onion_archival_index_list_sort_cmp(const void *_a, const void *_b) +{ + const H5FD_onion_index_entry_t *a = (const H5FD_onion_index_entry_t *)_a; + const H5FD_onion_index_entry_t *b = (const H5FD_onion_index_entry_t *)_b; + + if (a->logi_page < b->logi_page) + return -1; + else if (a->logi_page > b->logi_page) + return 1; + return 0; +} /* end H5FD__onion_archival_index_list_sort_cmp() */ + +/*----------------------------------------------------------------------------- + * Function: H5FD__onion_merge_revision_index_into_archival_index + * + * Purpose: Merge index entries from revision index into archival index. + * + * If successful, the archival index is expanded 'behind the + * scenes' and new entries from the revision index are inserted. + * The archival index remains sorted in ascending order of logical + * address. + * + * The conversion to archival index changes logical pages in + * revision index entries to their logical addresses in-file. + * + * Return: SUCCEED/FAIL + *----------------------------------------------------------------------------- + */ +herr_t +H5FD__onion_merge_revision_index_into_archival_index(const H5FD_onion_revision_index_t *rix, + H5FD_onion_archival_index_t * aix) +{ + uint64_t n_kept = 0; + H5FD_onion_index_entry_t * kept_list = NULL; + H5FD_onion_archival_index_t new_aix = { + H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR, 0, /* page_size_log2 tbd */ + 0, /* n_entries */ + NULL, /* list pointer (allocated later) */ + }; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE; + + HDassert(rix); + HDassert(aix); + HDassert(H5FD__ONION_REVISION_INDEX_VERSION_CURR == rix->version); + HDassert(H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR == aix->version); + HDassert(aix->page_size_log2 == rix->page_size_log2); + + /* If the revision index is empty there is nothing to archive */ + if (rix->n_entries == 0) + goto done; + + /* Add all revision index entries to new archival list */ + new_aix.page_size_log2 = aix->page_size_log2; + + if (NULL == (new_aix.list = H5MM_calloc(rix->n_entries * sizeof(H5FD_onion_index_entry_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate new archival index list") + + for (uint64_t i = 0; i < rix->_hash_table_size; i++) { + const H5FD_onion_revision_index_hash_chain_node_t *node = NULL; + + for (node = rix->_hash_table[i]; node != NULL; node = node->next) { + HDmemcpy(&new_aix.list[new_aix.n_entries], &node->entry_data, sizeof(H5FD_onion_index_entry_t)); + new_aix.n_entries++; + } + } + + /* Sort the new archival list */ + HDqsort(new_aix.list, new_aix.n_entries, sizeof(H5FD_onion_index_entry_t), + H5FD__onion_archival_index_list_sort_cmp); + + /* Add the old archival index entries to a 'kept' list containing the + * old archival list entries that are not also included in the revision + * list. + * + * Note that kept_list will be NULL if there are no entries in the passed-in + * archival list. + */ + if (aix->n_entries > 0) + if (NULL == (kept_list = H5MM_calloc(aix->n_entries * sizeof(H5FD_onion_index_entry_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate larger archival index list") + + for (uint64_t i = 0; i < aix->n_entries; i++) { + const H5FD_onion_index_entry_t *entry = NULL; + + /* Add only if page not already added from revision index */ + if (H5FD__onion_archival_index_find(&new_aix, aix->list[i].logi_page, &entry) == 0) { + HDmemcpy(&kept_list[n_kept], &aix->list[i], sizeof(H5FD_onion_index_entry_t)); + n_kept++; + } + } + + /* Destroy the old archival list and replace with a list big enough to hold + * the revision list entries and the kept list entries + */ + H5MM_xfree(aix->list); + if (NULL == (aix->list = H5MM_calloc((new_aix.n_entries + n_kept) * sizeof(H5FD_onion_index_entry_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate exact-size archival index list") + + /* Copy (new) revision list entries to replacement list */ + HDmemcpy(aix->list, new_aix.list, sizeof(H5FD_onion_index_entry_t) * new_aix.n_entries); + aix->n_entries = new_aix.n_entries; + + /* Copy (old) kept archival list entries to replacement list */ + if (n_kept > 0) { + HDmemcpy(&aix->list[aix->n_entries], kept_list, sizeof(H5FD_onion_index_entry_t) * n_kept); + aix->n_entries += n_kept; + } + + /* Sort this list */ + HDqsort(aix->list, aix->n_entries, sizeof(H5FD_onion_index_entry_t), + H5FD__onion_archival_index_list_sort_cmp); + +done: + /* Free the temporary lists */ + H5MM_xfree(kept_list); + H5MM_xfree(new_aix.list); + + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__onion_merge_revision_index_into_archival_index() */ diff --git a/src/H5FDonion_index.h b/src/H5FDonion_index.h new file mode 100644 index 0000000..0850537 --- /dev/null +++ b/src/H5FDonion_index.h @@ -0,0 +1,146 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5FDonion_index_H +#define H5FDonion_index_H + +#define H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR 1 + +/* Number of bytes to encode fixed-size components */ +#define H5FD__ONION_ENCODED_SIZE_INDEX_ENTRY 20 +#define H5FD__ONION_ENCODED_SIZE_RECORD_POINTER 20 +#define H5FD__ONION_ENCODED_SIZE_REVISION_RECORD 68 + +#define H5FD__ONION_REVISION_INDEX_HASH_CHAIN_NODE_VERSION_CURR 1 +#define H5FD__ONION_REVISION_INDEX_STARTING_SIZE_LOG2 10 /* 2^n slots */ +#define H5FD__ONION_REVISION_INDEX_VERSION_CURR 1 + +#define H5FD__ONION_REVISION_RECORD_SIGNATURE "ORRS" +#define H5FD__ONION_REVISION_RECORD_VERSION_CURR 1 + +/* + * Onion Virtual File Driver (VFD) + * + * Purpose: Interface for the archival and revision indexes + */ + +/*----------------------------------------------------------------------------- + * + * Structure H5FD__onion_index_entry + * + * Purpose: Map a page in the logical file to a 'physical address' in the + * backing store. + * + * logi_page: Page 'id' in the logical file. + * + * phys_addr: Address/offset of start of page in the backing store. + * + *----------------------------------------------------------------------------- + */ +typedef struct H5FD_onion_index_entry_t { + uint64_t logi_page; + haddr_t phys_addr; +} H5FD_onion_index_entry_t; + +/*----------------------------------------------------------------------------- + * + * Structure H5FD__onion_archival_index + * + * Purpose: Encapsulate archival index and associated data. + * Convenience structure with sanity-checking components. + * + * version: Future-proofing identifier. Informs struct membership. + * Must equal H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR to be + * considered valid. + * + * page_size: Interval to which the `logi_page` component of each list + * entry must align. + * Value is taken from the onion history data; must not change + * following onionization or file or creation of onion file. + * + * n_entries: Number of entries in the list. + * + * list: Pointer to array of archival index entries. + * Cannot be NULL. + * Entries must be sorted by `logi_page_id` in ascending order. + * + *----------------------------------------------------------------------------- + */ +typedef struct H5FD_onion_archival_index_t { + uint8_t version; + uint32_t page_size_log2; + uint64_t n_entries; + H5FD_onion_index_entry_t *list; +} H5FD_onion_archival_index_t; + +/* data structure for storing index entries at a hash key collision */ +/* version 1 implements a singly-linked list */ +typedef struct H5FD_onion_revision_index_hash_chain_node_t H5FD_onion_revision_index_hash_chain_node_t; +struct H5FD_onion_revision_index_hash_chain_node_t { + uint8_t version; + H5FD_onion_index_entry_t entry_data; + H5FD_onion_revision_index_hash_chain_node_t *next; +}; + +typedef struct H5FD_onion_revision_index_t { + uint8_t version; + uint32_t page_size_log2; + uint64_t n_entries; /* count of all entries in table */ + uint64_t _hash_table_size; /* 'slots' in hash table */ + uint64_t _hash_table_size_log2; /* 2^(n) -> 'slots' in hash table */ + uint64_t _hash_table_n_keys_populated; /* count of slots not NULL */ + H5FD_onion_revision_index_hash_chain_node_t **_hash_table; +} H5FD_onion_revision_index_t; + +/* In-memory representation of the on-store revision record. + */ +typedef struct H5FD_onion_revision_record_t { + uint8_t version; + uint64_t revision_num; + uint64_t parent_revision_num; + char time_of_creation[16]; + uint64_t logi_eof; + H5FD_onion_archival_index_t archival_index; + uint32_t comment_size; + char * comment; + uint32_t checksum; +} H5FD_onion_revision_record_t; + +#ifdef __cplusplus +extern "C" { +#endif +H5_DLL herr_t H5FD__onion_ingest_revision_record(H5FD_onion_revision_record_t *r_out, H5FD_t *raw_file, + const H5FD_onion_history_t *history, uint64_t revision_num); + +H5_DLL hbool_t H5FD__onion_archival_index_is_valid(const H5FD_onion_archival_index_t *); +H5_DLL int H5FD__onion_archival_index_find(const H5FD_onion_archival_index_t *, uint64_t, + const H5FD_onion_index_entry_t **); + +H5_DLL H5FD_onion_revision_index_t *H5FD__onion_revision_index_init(uint32_t page_size); +H5_DLL herr_t H5FD__onion_revision_index_destroy(H5FD_onion_revision_index_t *); +H5_DLL herr_t H5FD__onion_revision_index_insert(H5FD_onion_revision_index_t *, + const H5FD_onion_index_entry_t *); +H5_DLL int H5FD__onion_revision_index_find(const H5FD_onion_revision_index_t *, uint64_t, + const H5FD_onion_index_entry_t **); + +H5_DLL herr_t H5FD__onion_merge_revision_index_into_archival_index(const H5FD_onion_revision_index_t *, + H5FD_onion_archival_index_t *); + +H5_DLL uint64_t H5FD__onion_revision_record_decode(unsigned char *, H5FD_onion_revision_record_t *); +H5_DLL uint64_t H5FD__onion_revision_record_encode(H5FD_onion_revision_record_t *, unsigned char *, + uint32_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* H5FDonion_index_H */ diff --git a/src/H5FDonion_priv.h b/src/H5FDonion_priv.h index 63a7049..da4b2d1 100644 --- a/src/H5FDonion_priv.h +++ b/src/H5FDonion_priv.h @@ -21,186 +21,7 @@ #ifndef H5FDonion_priv_H #define H5FDonion_priv_H -/* - * INTERNAL MACROS AND DEFINITIONS - */ - -#define H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR 1 - -/* Number of bytes to encode fixed-size components */ -#define H5FD__ONION_ENCODED_SIZE_HEADER 40 -#define H5FD__ONION_ENCODED_SIZE_INDEX_ENTRY 20 -#define H5FD__ONION_ENCODED_SIZE_RECORD_POINTER 20 -#define H5FD__ONION_ENCODED_SIZE_REVISION_RECORD 68 -#define H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY 20 - -/* Flags must align exactly one per bit, up to 24 bits */ -#define H5FD__ONION_HEADER_FLAG_WRITE_LOCK 0x1 -#define H5FD__ONION_HEADER_FLAG_DIVERGENT_HISTORY 0x2 -#define H5FD__ONION_HEADER_FLAG_PAGE_ALIGNMENT 0x4 -#define H5FD__ONION_HEADER_SIGNATURE "OHDH" -#define H5FD__ONION_HEADER_VERSION_CURR 1 - -#define H5FD__ONION_REVISION_INDEX_HASH_CHAIN_NODE_VERSION_CURR 1 -#define H5FD__ONION_REVISION_INDEX_STARTING_SIZE_LOG2 10 /* 2^n slots */ -#define H5FD__ONION_REVISION_INDEX_VERSION_CURR 1 - -#define H5FD__ONION_REVISION_RECORD_SIGNATURE "ORRS" -#define H5FD__ONION_REVISION_RECORD_VERSION_CURR 1 - -#define H5FD__ONION_WHOLE_HISTORY_SIGNATURE "OWHS" -#define H5FD__ONION_WHOLE_HISTORY_VERSION_CURR 1 - -/* - * INTERNAL STRUCTURE DEFINITIONS - */ - -/*----------------------------------------------------------------------------- - * - * Structure H5FD__onion_index_entry - * - * Purpose: Map a page in the logical file to a 'physical address' in the - * backing store. - * - * logi_page: Page 'id' in the logical file. - * - * phys_addr: Address/offset of start of page in the backing store. - * - *----------------------------------------------------------------------------- - */ -typedef struct H5FD_onion_index_entry_t { - uint64_t logi_page; - uint64_t phys_addr; -} H5FD_onion_index_entry_t; - -/*----------------------------------------------------------------------------- - * - * Structure H5FD__onion_archival_index - * - * Purpose: Encapsulate archival index and associated data. - * Convenience structure with sanity-checking components. - * - * version: Future-proofing identifier. Informs struct membership. - * Must equal H5FD__ONION_ARCHIVAL_INDEX_VERSION_CURR to be - * considered valid. - * - * page_size: Interval to which the `logi_page` component of each list - * entry must align. - * Value is taken from the onion history data; must not change - * following onionization or file or creation of onion file. - * - * n_entries: Number of entries in the list. - * - * list: Pointer to array of archival index entries. - * Cannot be NULL. - * Entries must be sorted by `logi_page_id` in ascending order. - * - *----------------------------------------------------------------------------- - */ -typedef struct H5FD_onion_archival_index_t { - uint8_t version; - uint32_t page_size_log2; - uint64_t n_entries; - H5FD_onion_index_entry_t *list; -} H5FD_onion_archival_index_t; - -/* data structure for storing index entries at a hash key collision */ -/* version 1 implements a singly-linked list */ -typedef struct H5FD_onion_revision_index_hash_chain_node_t H5FD_onion_revision_index_hash_chain_node_t; -struct H5FD_onion_revision_index_hash_chain_node_t { - uint8_t version; - H5FD_onion_index_entry_t entry_data; - H5FD_onion_revision_index_hash_chain_node_t *next; -}; - -typedef struct H5FD__onion_revision_index_t { - uint8_t version; - uint32_t page_size_log2; - uint64_t n_entries; /* count of all entries in table */ - uint64_t _hash_table_size; /* 'slots' in hash table */ - uint64_t _hash_table_size_log2; /* 2^(n) -> 'slots' in hash table */ - uint64_t _hash_table_n_keys_populated; /* count of slots not NULL */ - H5FD_onion_revision_index_hash_chain_node_t **_hash_table; -} H5FD__onion_revision_index_t; - -/* In-memory representation of the on-store onion history file header. - */ -typedef struct H5FD_onion_history_header_t { - uint8_t version; - uint32_t flags; /* at most three bytes used! */ - uint32_t page_size; - uint64_t origin_eof; /* size of the 'original' canonical file */ - uint64_t whole_history_addr; - uint64_t whole_history_size; - uint32_t checksum; -} H5FD_onion_history_header_t; - -/* In-memory representation of the on-store revision record. - */ -typedef struct H5FD_onion_revision_record_t { - uint8_t version; - uint64_t revision_num; - uint64_t parent_revision_num; - char time_of_creation[16]; - uint64_t logi_eof; - H5FD_onion_archival_index_t archival_index; - uint32_t comment_size; - char * comment; - uint32_t checksum; -} H5FD_onion_revision_record_t; - -/* In-memory representation of the on-store revision record pointer. - * Used in the whole-history. - */ -typedef struct H5FD_onion_record_pointer_t { - uint64_t phys_addr; - uint64_t record_size; - uint32_t checksum; -} H5FD_onion_record_pointer_t; - -/* In-memory representation of the on-store whole-history record/summary. - */ -typedef struct H5FD_onion_whole_history_t { - uint8_t version; - uint64_t n_revisions; - H5FD_onion_record_pointer_t *record_pointer_list; - uint32_t checksum; -} H5FD_onion_whole_history_t; - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * INTERNAL FUNCTION DECLARATIONS - */ - -H5_DLL hbool_t H5FD_onion_archival_index_is_valid(const H5FD_onion_archival_index_t *); -H5_DLL int H5FD_onion_archival_index_find(const H5FD_onion_archival_index_t *, uint64_t, - const H5FD_onion_index_entry_t **); - -H5_DLL H5FD__onion_revision_index_t *H5FD_onion_revision_index_init(uint32_t page_size); -H5_DLL herr_t H5FD_onion_revision_index_destroy(H5FD__onion_revision_index_t *); -H5_DLL herr_t H5FD_onion_revision_index_insert(H5FD__onion_revision_index_t *, - const H5FD_onion_index_entry_t *); -H5_DLL int H5FD_onion_revision_index_find(const H5FD__onion_revision_index_t *, uint64_t, - const H5FD_onion_index_entry_t **); - -H5_DLL herr_t H5FD_onion_merge_revision_index_into_archival_index(const H5FD__onion_revision_index_t *, - H5FD_onion_archival_index_t *); - -H5_DLL uint64_t H5FD_onion_history_header_decode(unsigned char *, H5FD_onion_history_header_t *); -H5_DLL uint64_t H5FD_onion_history_header_encode(H5FD_onion_history_header_t *, unsigned char *, uint32_t *); - -H5_DLL uint64_t H5FD_onion_revision_record_decode(unsigned char *, H5FD_onion_revision_record_t *); -H5_DLL uint64_t H5FD_onion_revision_record_encode(H5FD_onion_revision_record_t *, unsigned char *, - uint32_t *); - -H5_DLL uint64_t H5FD_onion_whole_history_decode(unsigned char *, H5FD_onion_whole_history_t *); -H5_DLL uint64_t H5FD_onion_whole_history_encode(H5FD_onion_whole_history_t *, unsigned char *, uint32_t *); - -#ifdef __cplusplus -} -#endif +#include "H5FDonion_history.h" +#include "H5FDonion_index.h" #endif /* H5FDonion_priv_H */ diff --git a/src/Makefile.am b/src/Makefile.am index d289278..fc6ccfd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -61,8 +61,9 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5lib_settings.c H5system.c \ H5Fsuper.c H5Fsuper_cache.c H5Ftest.c \ H5FA.c H5FAcache.c H5FAdbg.c H5FAdblock.c H5FAdblkpage.c H5FAhdr.c \ H5FAint.c H5FAstat.c H5FAtest.c \ - H5FD.c H5FDcore.c H5FDfamily.c H5FDint.c H5FDlog.c \ - H5FDmulti.c H5FDonion.c H5FDperform.c H5FDsec2.c H5FDspace.c \ + H5FD.c H5FDcore.c H5FDfamily.c H5FDint.c H5FDlog.c H5FDmulti.c \ + H5FDonion.c H5FDonion_history.c H5FDonion_index.c \ + H5FDperform.c H5FDsec2.c H5FDspace.c \ H5FDsplitter.c H5FDstdio.c H5FDtest.c \ H5FL.c H5FO.c H5FS.c H5FScache.c H5FSdbg.c H5FSint.c H5FSsection.c \ H5FSstat.c H5FStest.c \ diff --git a/test/onion.c b/test/onion.c index f5efcf8..7e2a17d 100644 --- a/test/onion.c +++ b/test/onion.c @@ -196,33 +196,33 @@ test_archival_index(void) /* Invalid version should fail */ aix.version++; - if (H5FD_onion_archival_index_is_valid(&aix)) + 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)) + 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)) + 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)) + 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)) + 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)) + if (H5FD__onion_archival_index_is_valid(&aix)) TEST_ERROR; /* @@ -231,13 +231,13 @@ test_archival_index(void) /* Sorted list should pass */ aix.list = sorted; - if (!H5FD_onion_archival_index_is_valid(&aix)) + 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)) + if (!H5FD__onion_archival_index_is_valid(&aix)) TEST_ERROR; /* @@ -248,14 +248,14 @@ test_archival_index(void) aix.n_entries = 8; /* Check that address not in array returns zero */ - if (H5FD_onion_archival_index_find(&aix, 3, &entry_out_p) != 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; /* Address found should return 1 */ - if (H5FD_onion_archival_index_find(&aix, 4, &entry_out_p) != 1) + if (H5FD__onion_archival_index_find(&aix, 4, &entry_out_p) != 1) TEST_ERROR; /* Pointer should be set */ if (NULL == entry_out_p) @@ -272,11 +272,11 @@ test_archival_index(void) aix.n_entries = 4; /* Address not in array should return 0 */ - if (H5FD_onion_archival_index_find(&aix, 1, &entry_out_p) != 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) + if (H5FD__onion_archival_index_find(&aix, 101, &entry_out_p) != 0) TEST_ERROR; /* @@ -286,7 +286,7 @@ test_archival_index(void) 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) + if (H5FD__onion_archival_index_find(&aix, 3, &entry_out_p) != 0) TEST_ERROR; /* Pointer should remain unset */ if (entry_out_p != NULL) @@ -311,8 +311,8 @@ error: static int test_revision_index(void) { - H5FD__onion_revision_index_t *rix_p = NULL; - H5FD_onion_index_entry_t entry = { + H5FD_onion_revision_index_t *rix_p = NULL; + H5FD_onion_index_entry_t entry = { 42, /* logi_page */ 111112, /* phys_addr */ }; @@ -322,7 +322,7 @@ test_revision_index(void) /* Test index creation */ - if (NULL == (rix_p = H5FD_onion_revision_index_init(ONION_TEST_PAGE_SIZE_5))) + 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; @@ -331,18 +331,18 @@ test_revision_index(void) /* Test missed search */ - if (H5FD_onion_revision_index_find(rix_p, entry.logi_page, &entry_out_p) != 0) + if (H5FD__onion_revision_index_find(rix_p, entry.logi_page, &entry_out_p) != 0) TEST_ERROR; /* Test successful insertion and lookup */ /* Insertion failed */ - if (H5FD_onion_revision_index_insert(rix_p, &entry) < 0) + 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.logi_page, &entry_out_p) < 0) + if (H5FD__onion_revision_index_find(rix_p, entry.logi_page, &entry_out_p) < 0) TEST_ERROR; /* Failure to set output parameter */ if (NULL == entry_out_p) @@ -350,20 +350,20 @@ test_revision_index(void) if (entry.logi_page != entry_out_p->logi_page) TEST_ERROR; /* Seeking missing page should miss */ - if (H5FD_onion_revision_index_find(rix_p, entry.logi_page + 1, &entry_out_p) != 0) + if (H5FD__onion_revision_index_find(rix_p, entry.logi_page + 1, &entry_out_p) != 0) TEST_ERROR; /* Test / demonstrate stored entry independent of user object */ entry.logi_page = 100; entry.phys_addr = 101; - if (H5FD_onion_revision_index_insert(rix_p, &entry) < 0) + if (H5FD__onion_revision_index_insert(rix_p, &entry) < 0) TEST_ERROR; if (2 != rix_p->n_entries) TEST_ERROR; entry.logi_page = 500; entry.phys_addr = 501; - if (H5FD_onion_revision_index_find(rix_p, 100, &entry_out_p) < 0) + if (H5FD__onion_revision_index_find(rix_p, 100, &entry_out_p) < 0) TEST_ERROR; if (100 != entry_out_p->logi_page || 101 != entry_out_p->phys_addr) TEST_ERROR; @@ -373,7 +373,7 @@ test_revision_index(void) /* Error cases */ entry.logi_page = 100; /* phys_addr still 501, checksum bbbbbbbb */ - if (H5FD_onion_revision_index_insert(rix_p, &entry) >= 0) + if (H5FD__onion_revision_index_insert(rix_p, &entry) >= 0) TEST_ERROR; /* all components but sum must match */ entry.phys_addr = 101; @@ -381,18 +381,18 @@ test_revision_index(void) entry.logi_page = 100; entry.phys_addr = 101; - if (H5FD_onion_revision_index_insert(rix_p, &entry) < 0) + 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) + if (H5FD__onion_revision_index_find(rix_p, 100, &entry_out_p) < 0) TEST_ERROR; if (100 != entry_out_p->logi_page || 101 != entry_out_p->phys_addr) TEST_ERROR; - if (H5FD_onion_revision_index_destroy(rix_p) < 0) + if (H5FD__onion_revision_index_destroy(rix_p) < 0) TEST_ERROR; PASSED(); @@ -400,7 +400,7 @@ test_revision_index(void) error: if (rix_p != NULL) - (void)H5FD_onion_revision_index_destroy(rix_p); + (void)H5FD__onion_revision_index_destroy(rix_p); return -1; } /* end test_revision_index() */ @@ -418,8 +418,8 @@ error: static int test_revision_index_collisions(void) { - H5FD__onion_revision_index_t *rix_p = NULL; - H5FD_onion_index_entry_t entry = { + H5FD_onion_revision_index_t *rix_p = NULL; + H5FD_onion_index_entry_t entry = { 0, /* logi_page */ 0, /* phys_addr */ }; @@ -429,13 +429,13 @@ test_revision_index_collisions(void) TESTING("revision index collisions"); - if (NULL == (rix_p = H5FD_onion_revision_index_init(ONION_TEST_PAGE_SIZE_5))) + 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.logi_page = U64_EXP2(i) + offset_from_power; - if (H5FD_onion_revision_index_insert(rix_p, &entry) < 0) + if (H5FD__onion_revision_index_insert(rix_p, &entry) < 0) TEST_ERROR; } @@ -445,13 +445,13 @@ test_revision_index_collisions(void) 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) + 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) + if (H5FD__onion_revision_index_destroy(rix_p) < 0) TEST_ERROR; PASSED(); @@ -459,7 +459,7 @@ test_revision_index_collisions(void) error: if (rix_p != NULL) - (void)H5FD_onion_revision_index_destroy(rix_p); + (void)H5FD__onion_revision_index_destroy(rix_p); return -1; } /* end test_revision_index_collisions() */ @@ -479,8 +479,8 @@ error: static int test_revision_index_resizing(void) { - H5FD__onion_revision_index_t *rix_p = NULL; - H5FD_onion_index_entry_t entry = { + H5FD_onion_revision_index_t *rix_p = NULL; + H5FD_onion_index_entry_t entry = { 0, /* logi_page */ 0, /* phys_addr */ }; @@ -489,13 +489,13 @@ test_revision_index_resizing(void) TESTING("revision index resizing"); - if (NULL == (rix_p = H5FD_onion_revision_index_init(ONION_TEST_PAGE_SIZE_5))) + 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.logi_page = i; entry.phys_addr = ((uint64_t)(-1) - i); - if (H5FD_onion_revision_index_insert(rix_p, &entry) < 0) + if (H5FD__onion_revision_index_insert(rix_p, &entry) < 0) TEST_ERROR; } @@ -505,13 +505,13 @@ test_revision_index_resizing(void) 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) + 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) + if (H5FD__onion_revision_index_destroy(rix_p) < 0) TEST_ERROR; PASSED(); @@ -519,7 +519,7 @@ test_revision_index_resizing(void) error: if (rix_p != NULL) - (void)H5FD_onion_revision_index_destroy(rix_p); + (void)H5FD__onion_revision_index_destroy(rix_p); return -1; } /* end test_revision_index_resizing() */ @@ -536,8 +536,8 @@ error: static int test_revision_index_to_archival_index(void) { - H5FD__onion_revision_index_t *rix_p = NULL; - H5FD_onion_index_entry_t rix_entry = { + H5FD_onion_revision_index_t *rix_p = NULL; + H5FD_onion_index_entry_t rix_entry = { 0, /* logi_page */ 0, /* phys_addr */ }; @@ -555,7 +555,7 @@ test_revision_index_to_archival_index(void) * SETUP */ - if (NULL == (rix_p = H5FD_onion_revision_index_init(ONION_TEST_PAGE_SIZE_5))) + if (NULL == (rix_p = H5FD__onion_revision_index_init(ONION_TEST_PAGE_SIZE_5))) TEST_ERROR; /* Add scattered entries in reverse order. */ @@ -564,7 +564,7 @@ test_revision_index_to_archival_index(void) rix_entry.logi_page = n; rix_entry.phys_addr = n * 13; - if (H5FD_onion_revision_index_insert(rix_p, &rix_entry) < 0) + if (H5FD__onion_revision_index_insert(rix_p, &rix_entry) < 0) TEST_ERROR; } @@ -576,10 +576,10 @@ test_revision_index_to_archival_index(void) /* Successful merge into empty archival index */ - if (H5FD_onion_merge_revision_index_into_archival_index(rix_p, &aix) < 0) + if (H5FD__onion_merge_revision_index_into_archival_index(rix_p, &aix) < 0) TEST_ERROR; - if (!H5FD_onion_archival_index_is_valid(&aix)) + if (!H5FD__onion_archival_index_is_valid(&aix)) TEST_ERROR; if (n_insert != aix.n_entries) @@ -609,12 +609,12 @@ test_revision_index_to_archival_index(void) aix.list[1].phys_addr = (2003 * (n_insert + 1) + 47) * 13; aix.n_entries = 2; - if (!H5FD_onion_archival_index_is_valid(&aix)) + if (!H5FD__onion_archival_index_is_valid(&aix)) TEST_ERROR; - if (H5FD_onion_merge_revision_index_into_archival_index(rix_p, &aix) < 0) + if (H5FD__onion_merge_revision_index_into_archival_index(rix_p, &aix) < 0) TEST_ERROR; - if (!H5FD_onion_archival_index_is_valid(&aix)) + if (!H5FD__onion_archival_index_is_valid(&aix)) TEST_ERROR; if (n_insert + 2 != aix.n_entries) @@ -645,13 +645,13 @@ test_revision_index_to_archival_index(void) aix.list[1].phys_addr = 101; aix.n_entries = 2; - if (!H5FD_onion_archival_index_is_valid(&aix)) + if (!H5FD__onion_archival_index_is_valid(&aix)) TEST_ERROR; - if (H5FD_onion_merge_revision_index_into_archival_index(rix_p, &aix) < 0) + if (H5FD__onion_merge_revision_index_into_archival_index(rix_p, &aix) < 0) TEST_ERROR; - if (!H5FD_onion_archival_index_is_valid(&aix)) + if (!H5FD__onion_archival_index_is_valid(&aix)) TEST_ERROR; if (n_insert != aix.n_entries) @@ -671,7 +671,7 @@ test_revision_index_to_archival_index(void) /* CLEANUP */ - if (H5FD_onion_revision_index_destroy(rix_p) < 0) + if (H5FD__onion_revision_index_destroy(rix_p) < 0) TEST_ERROR; H5MM_xfree(aix.list); @@ -680,7 +680,7 @@ test_revision_index_to_archival_index(void) error: if (rix_p) - (void)H5FD_onion_revision_index_destroy(rix_p); + (void)H5FD__onion_revision_index_destroy(rix_p); H5MM_xfree(aix.list); return -1; @@ -894,8 +894,8 @@ test_header_encode_decode(void) '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, /* whole_history_addr */ - 88, 0, 0, 0, 0, 0, 0, 0, /* whole_history_size */ + 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; @@ -915,10 +915,10 @@ test_header_encode_decode(void) hdr.version = H5FD__ONION_HEADER_VERSION_CURR; hdr.flags = 12; hdr.origin_eof = 8589934609ull, hdr.page_size = 4096; - hdr.whole_history_addr = 123456; - hdr.whole_history_size = 88; + hdr.history_addr = 123456; + hdr.history_size = 88; - if (H5FD_onion_history_header_encode(&hdr, buf, &sum_out) != H5FD__ONION_ENCODED_SIZE_HEADER) + if (H5FD__onion_history_header_encode(&hdr, buf, &sum_out) != H5FD__ONION_ENCODED_SIZE_HEADER) TEST_ERROR; if (sum != sum_out) @@ -931,11 +931,11 @@ test_header_encode_decode(void) } } - hdr_out.version = H5FD__ONION_HEADER_VERSION_CURR; - hdr_out.flags = 0; - hdr_out.page_size = 0; - hdr_out.whole_history_addr = 0; - hdr_out.whole_history_size = 0; + 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. */ @@ -943,7 +943,7 @@ test_header_encode_decode(void) exp[3] = 'X'; /* invalidate encoded signature */ H5E_BEGIN_TRY { - size_ret = H5FD_onion_history_header_decode(exp, &hdr_out); + size_ret = H5FD__onion_history_header_decode(exp, &hdr_out); } H5E_END_TRY; if (0 != size_ret) @@ -957,7 +957,7 @@ test_header_encode_decode(void) exp[4] = 0; /* encoded version 0?!? */ H5E_BEGIN_TRY { - size_ret = H5FD_onion_history_header_decode(exp, &hdr_out); + size_ret = H5FD__onion_history_header_decode(exp, &hdr_out); } H5E_END_TRY; if (0 != size_ret) @@ -966,7 +966,7 @@ test_header_encode_decode(void) exp[4] = H5FD__ONION_HEADER_VERSION_CURR + 1; /* encoded super-version?! */ H5E_BEGIN_TRY { - size_ret = H5FD_onion_history_header_decode(exp, &hdr_out); + size_ret = H5FD__onion_history_header_decode(exp, &hdr_out); } H5E_END_TRY; if (0 != size_ret) @@ -977,7 +977,7 @@ test_header_encode_decode(void) /* Valid header can be decoded */ - if (H5FD_onion_history_header_decode(buf, &hdr_out) != H5FD__ONION_ENCODED_SIZE_HEADER) + if (H5FD__onion_history_header_decode(buf, &hdr_out) != H5FD__ONION_ENCODED_SIZE_HEADER) TEST_ERROR; if (H5FD__ONION_HEADER_VERSION_CURR != hdr_out.version) TEST_ERROR; @@ -985,9 +985,9 @@ test_header_encode_decode(void) TEST_ERROR; if (hdr.page_size != hdr_out.page_size) TEST_ERROR; - if (hdr.whole_history_addr != hdr_out.whole_history_addr) + if (hdr.history_addr != hdr_out.history_addr) TEST_ERROR; - if (hdr.whole_history_size != hdr_out.whole_history_size) + if (hdr.history_size != hdr_out.history_size) TEST_ERROR; PASSED(); @@ -998,10 +998,10 @@ error: } /* end test_header_encode_decode() */ /*----------------------------------------------------------------------------- - * Function: test_whole_history_encode_decode_empty() + * Function: test_history_encode_decode_empty() * - * Purpose: Verify onion whole-history encoding and decoding behavior. - * Tests the case of the "empty" whole-history. + * Purpose: Verify onion history encoding and decoding behavior. + * Tests the case of the "empty" history. * Verifies behavior in standard error cases. * * Return: PASSED : 0 @@ -1009,7 +1009,7 @@ error: *----------------------------------------------------------------------------- */ static int -test_whole_history_encode_decode_empty(void) +test_history_encode_decode_empty(void) { unsigned char buf[32]; unsigned char exp[32] = { @@ -1017,30 +1017,30 @@ test_whole_history_encode_decode_empty(void) 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 sum = 0; - uint32_t sum_out = 0; - size_t i = 0; - uint64_t size_ret = 0; - H5FD_onion_whole_history_t whs = { + unsigned char * ptr = NULL; + uint32_t sum = 0; + uint32_t sum_out = 0; + size_t i = 0; + uint64_t size_ret = 0; + H5FD_onion_history_t history = { H5FD__ONION_WHOLE_HISTORY_VERSION_CURR, 0, /* n_revisions */ NULL, /* list */ 0, /* checksum */ }; - H5FD_onion_whole_history_t whs_out = { + H5FD_onion_history_t history_out = { H5FD__ONION_WHOLE_HISTORY_VERSION_CURR, 0, /* n_revisions */ NULL, /* list */ 0, /* checksum */ }; - TESTING("encode/decode whole-history (empty and failures)"); + TESTING("encode/decode history (empty and failures)"); /* Generage checksum but don't store it yet */ sum = H5_checksum_fletcher32(exp, H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY - 4); ptr = exp + H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY - 4; UINT32ENCODE(ptr, sum); - if (H5FD_onion_whole_history_encode(&whs, buf, &sum_out) != H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY) + if (H5FD__onion_history_encode(&history, buf, &sum_out) != H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY) TEST_ERROR; for (i = 0; i < 20; i++) { if (exp[i] != buf[i]) { @@ -1050,14 +1050,14 @@ test_whole_history_encode_decode_empty(void) } if (sum != sum_out) TEST_ERROR; - whs.checksum = sum; /* set to compare later */ + history.checksum = sum; /* set to compare later */ /* Invalid signature prevents decoding */ exp[3] = 'X'; /* invalidate encoded signature */ H5E_BEGIN_TRY { - size_ret = H5FD_onion_whole_history_decode(exp, &whs_out); + size_ret = H5FD__onion_history_decode(exp, &history_out); } H5E_END_TRY; if (0 != size_ret) @@ -1070,7 +1070,7 @@ test_whole_history_encode_decode_empty(void) exp[4] = 0; /* encoded version 0?!? */ H5E_BEGIN_TRY { - size_ret = H5FD_onion_whole_history_decode(exp, &whs_out); + size_ret = H5FD__onion_history_decode(exp, &history_out); } H5E_END_TRY; if (0 != size_ret) @@ -1079,7 +1079,7 @@ test_whole_history_encode_decode_empty(void) exp[4] = H5FD__ONION_WHOLE_HISTORY_VERSION_CURR + 1; H5E_BEGIN_TRY { - size_ret = H5FD_onion_whole_history_decode(exp, &whs_out); + size_ret = H5FD__onion_history_decode(exp, &history_out); } H5E_END_TRY; if (0 != size_ret) @@ -1089,15 +1089,15 @@ test_whole_history_encode_decode_empty(void) /* Valid summary can be decoded */ - if (H5FD_onion_whole_history_decode(buf, &whs_out) != H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY) + if (H5FD__onion_history_decode(buf, &history_out) != H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY) TEST_ERROR; - if (H5FD__ONION_WHOLE_HISTORY_VERSION_CURR != whs_out.version) + if (H5FD__ONION_WHOLE_HISTORY_VERSION_CURR != history_out.version) TEST_ERROR; - if (whs.n_revisions != whs_out.n_revisions) + if (history.n_revisions != history_out.n_revisions) TEST_ERROR; - if (whs.checksum != whs_out.checksum) + if (history.checksum != history_out.checksum) TEST_ERROR; - if (NULL != whs_out.record_pointer_list) + if (NULL != history_out.record_locs) TEST_ERROR; PASSED(); @@ -1105,12 +1105,12 @@ test_whole_history_encode_decode_empty(void) error: return -1; -} /* end test_whole_history_encode_decode_empty() */ +} /* end test_history_encode_decode_empty() */ /*----------------------------------------------------------------------------- - * Function: test_whole_history_encode_decode() + * Function: test_history_encode_decode() * - * Purpose: Verify onion whole-history encoding and decoding behavior. + * Purpose: Verify onion history encoding and decoding behavior. * Encode/decode with some set of revision record pointers. * * Return: PASSED : 0 @@ -1118,7 +1118,7 @@ error: *----------------------------------------------------------------------------- */ static int -test_whole_history_encode_decode(void) +test_history_encode_decode(void) { unsigned char *buf = NULL; unsigned char exp[80] = { @@ -1134,100 +1134,100 @@ test_whole_history_encode_decode(void) /* final checksum */ 0, 0, 0, 0 /* sum populated below */ }; - unsigned char * buf_p = NULL; - uint32_t sum_out = 0; - size_t i = 0; - H5FD_onion_whole_history_t whs = { + unsigned char * buf_p = NULL; + uint32_t sum_out = 0; + size_t i = 0; + H5FD_onion_history_t history = { H5FD__ONION_WHOLE_HISTORY_VERSION_CURR, 3, /* n_revisions */ NULL, /* list set below */ 0, /* checksum not set by us */ }; - H5FD_onion_whole_history_t whs_out = { + H5FD_onion_history_t history_out = { H5FD__ONION_WHOLE_HISTORY_VERSION_CURR, 0, /* n_revisions must start as zero */ NULL, /* list */ 0, /* checksum */ }; - uint64_t exp_size = - H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY + H5FD__ONION_ENCODED_SIZE_RECORD_POINTER * whs.n_revisions; + uint64_t exp_size = H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY + + H5FD__ONION_ENCODED_SIZE_RECORD_POINTER * history.n_revisions; - TESTING("encode/decode whole-history"); + TESTING("encode/decode history"); if (80 != exp_size) TEST_ERROR; - whs.record_pointer_list = HDcalloc(whs.n_revisions, sizeof(H5FD_onion_record_pointer_t)); - if (NULL == whs.record_pointer_list) + history.record_locs = HDcalloc(history.n_revisions, sizeof(H5FD_onion_record_loc_t)); + if (NULL == history.record_locs) TEST_ERROR; - /* must match values in exp */ - whs.record_pointer_list[0].phys_addr = 568ull; - whs.record_pointer_list[0].record_size = 238ull; - whs.record_pointer_list[1].phys_addr = 241017ull; - whs.record_pointer_list[1].record_size = 4555ull; - whs.record_pointer_list[2].phys_addr = 918153371232ull; - whs.record_pointer_list[2].record_size = 240ull; + /* 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 < whs.n_revisions; i++) { - uint64_t whs_pre = H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY - 4; - uint64_t ptr_pre = H5FD__ONION_ENCODED_SIZE_RECORD_POINTER - 4; - uint64_t ptr_size = H5FD__ONION_ENCODED_SIZE_RECORD_POINTER; + for (i = 0; i < history.n_revisions; i++) { + uint64_t history_pre = H5FD__ONION_ENCODED_SIZE_WHOLE_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 + whs_pre + ptr_size * i; - whs.record_pointer_list[i].checksum = H5_checksum_fletcher32(buf_p, ptr_pre); + 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, whs.record_pointer_list[i].checksum); + UINT32ENCODE(buf_p, history.record_locs[i].checksum); } /* Compute, populate, and store exp final sum */ - whs.checksum = H5_checksum_fletcher32(exp, exp_size - 4); - buf_p = exp + exp_size - 4; - UINT32ENCODE(buf_p, whs.checksum); + history.checksum = H5_checksum_fletcher32(exp, exp_size - 4); + buf_p = exp + exp_size - 4; + UINT32ENCODE(buf_p, history.checksum); if (NULL == (buf = HDmalloc(exp_size))) TEST_ERROR; - if (H5FD_onion_whole_history_encode(&whs, buf, &sum_out) != exp_size) + if (H5FD__onion_history_encode(&history, buf, &sum_out) != exp_size) TEST_ERROR; for (i = 0; i < exp_size; i++) { if (exp[i] != buf[i]) TEST_ERROR; } - if (whs.checksum != sum_out) + if (history.checksum != sum_out) TEST_ERROR; /* Initial decode, gets always-present components */ - whs_out.n_revisions = 0; /* must be initialized to 0 */ - if (H5FD_onion_whole_history_decode(exp, &whs_out) != exp_size) + 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_WHOLE_HISTORY_VERSION_CURR != whs_out.version) + if (H5FD__ONION_WHOLE_HISTORY_VERSION_CURR != history_out.version) TEST_ERROR; - if (whs.n_revisions != whs_out.n_revisions) + if (history.n_revisions != history_out.n_revisions) TEST_ERROR; /* Must be created by us */ - if (NULL != whs_out.record_pointer_list) + if (NULL != history_out.record_locs) TEST_ERROR; /* True decode requires allocating space for record pointers */ - whs_out.record_pointer_list = HDcalloc(whs_out.n_revisions, sizeof(H5FD_onion_record_pointer_t)); - if (NULL == whs_out.record_pointer_list) + history_out.record_locs = HDcalloc(history_out.n_revisions, sizeof(H5FD_onion_record_loc_t)); + if (NULL == history_out.record_locs) TEST_ERROR; - if (H5FD_onion_whole_history_decode(exp, &whs_out) != exp_size) + if (H5FD__onion_history_decode(exp, &history_out) != exp_size) TEST_ERROR; - if (H5FD__ONION_WHOLE_HISTORY_VERSION_CURR != whs_out.version) + if (H5FD__ONION_WHOLE_HISTORY_VERSION_CURR != history_out.version) TEST_ERROR; - if (whs.n_revisions != whs_out.n_revisions) + if (history.n_revisions != history_out.n_revisions) TEST_ERROR; - if (whs.checksum != whs_out.checksum) + if (history.checksum != history_out.checksum) TEST_ERROR; - if (NULL == whs_out.record_pointer_list) + if (NULL == history_out.record_locs) TEST_ERROR; - for (i = 0; i < whs.n_revisions; i++) { - H5FD_onion_record_pointer_t exp_rp = whs.record_pointer_list[i]; - H5FD_onion_record_pointer_t act_rp = whs_out.record_pointer_list[i]; + 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; @@ -1237,20 +1237,20 @@ test_whole_history_encode_decode(void) TEST_ERROR; } - HDfree(whs_out.record_pointer_list); + HDfree(history_out.record_locs); HDfree(buf); - HDfree(whs.record_pointer_list); + HDfree(history.record_locs); PASSED(); return 0; error: - HDfree(whs_out.record_pointer_list); + HDfree(history_out.record_locs); HDfree(buf); - HDfree(whs.record_pointer_list); + HDfree(history.record_locs); return -1; -} /* end test_whole_history_encode_decode() */ +} /* end test_history_encode_decode() */ /*----------------------------------------------------------------------------- * @@ -1380,7 +1380,7 @@ test_revision_record_encode_decode(void) /* Test encode */ - if (H5FD_onion_revision_record_encode(&record, buf, &sum_out) != exp_size) + if (H5FD__onion_revision_record_encode(&record, buf, &sum_out) != exp_size) TEST_ERROR; hbool_t badness = FALSE; @@ -1419,7 +1419,7 @@ test_revision_record_encode_decode(void) exp[2] = 'Y'; H5E_BEGIN_TRY { - size_ret = H5FD_onion_revision_record_decode(exp, &r_out); + size_ret = H5FD__onion_revision_record_decode(exp, &r_out); } H5E_END_TRY; if (0 != size_ret) @@ -1430,7 +1430,7 @@ test_revision_record_encode_decode(void) exp[4] = 0; H5E_BEGIN_TRY { - size_ret = H5FD_onion_revision_record_decode(exp, &r_out); + size_ret = H5FD__onion_revision_record_decode(exp, &r_out); } H5E_END_TRY; if (0 != size_ret) @@ -1440,7 +1440,7 @@ test_revision_record_encode_decode(void) exp[4] = H5FD__ONION_REVISION_RECORD_VERSION_CURR + 1; H5E_BEGIN_TRY { - size_ret = H5FD_onion_revision_record_decode(exp, &r_out); + size_ret = H5FD__onion_revision_record_decode(exp, &r_out); } H5E_END_TRY; if (0 != size_ret) @@ -1450,7 +1450,7 @@ test_revision_record_encode_decode(void) /* Test successful decode */ /* Initial decode; get variable-length component sizes */ - if (H5FD_onion_revision_record_decode(exp, &r_out) != exp_size) + if (H5FD__onion_revision_record_decode(exp, &r_out) != exp_size) TEST_ERROR; if (record.comment_size != r_out.comment_size) TEST_ERROR; @@ -1466,7 +1466,7 @@ test_revision_record_encode_decode(void) TEST_ERROR; /* Decode into all components */ - if (H5FD_onion_revision_record_decode(exp, &r_out) != exp_size) + 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; @@ -1590,7 +1590,7 @@ verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filt { unsigned char * buf = NULL; /* allocated area for actual file bytes */ H5FD_onion_history_header_t hdr_out; - H5FD_onion_whole_history_t whs_out; + H5FD_onion_history_t history_out; H5FD_onion_revision_record_t rev_out; uint64_t filesize = 0; uint64_t readsize = 0; @@ -1598,9 +1598,9 @@ verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filt hdr_out.version = H5FD__ONION_HEADER_VERSION_CURR; - whs_out.version = H5FD__ONION_WHOLE_HISTORY_VERSION_CURR; - whs_out.n_revisions = 0; - whs_out.record_pointer_list = NULL; + history_out.version = H5FD__ONION_WHOLE_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; @@ -1617,7 +1617,7 @@ verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filt if (H5FDread(raw_file, H5FD_MEM_DRAW, H5P_DEFAULT, 0, readsize, buf) < 0) TEST_ERROR; - readsize = H5FD_onion_history_header_decode(buf, &hdr_out); + readsize = H5FD__onion_history_header_decode(buf, &hdr_out); if (0 == readsize) TEST_ERROR; if (H5FD__ONION_HEADER_VERSION_CURR != hdr_out.version) @@ -1628,7 +1628,7 @@ verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filt TEST_ERROR; if (filter->page_size != hdr_out.page_size) TEST_ERROR; - if (hdr_out.whole_history_addr + hdr_out.whole_history_size != filesize) + if (hdr_out.history_addr + hdr_out.history_size != filesize) TEST_ERROR; if (filter->origin_eof != hdr_out.origin_eof) TEST_ERROR; @@ -1636,42 +1636,42 @@ verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filt HDfree(buf); buf = NULL; - /* Ingest whole-history */ + /* Ingest history */ - readsize = hdr_out.whole_history_size; + readsize = hdr_out.history_size; if (NULL == (buf = HDmalloc(readsize * sizeof(unsigned char)))) TEST_ERROR; - if (H5FDread(raw_file, H5FD_MEM_DRAW, H5P_DEFAULT, hdr_out.whole_history_addr, readsize, buf) < 0) + 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_whole_history_decode(buf, &whs_out); + readsize = H5FD__onion_history_decode(buf, &history_out); if (0 == readsize) TEST_ERROR; - if (H5FD__ONION_WHOLE_HISTORY_VERSION_CURR != whs_out.version) + if (H5FD__ONION_WHOLE_HISTORY_VERSION_CURR != history_out.version) TEST_ERROR; - if (HDmemcmp(&whs_out.checksum, &buf[readsize - 4], 4) != 0) + if (HDmemcmp(&history_out.checksum, &buf[readsize - 4], 4) != 0) TEST_ERROR; - if (whs_out.checksum != H5_checksum_fletcher32(buf, readsize - 4)) + if (history_out.checksum != H5_checksum_fletcher32(buf, readsize - 4)) TEST_ERROR; - if (filter->n_revisions != whs_out.n_revisions) + if (filter->n_revisions != history_out.n_revisions) TEST_ERROR; /* Final read, populate pointers to revision records */ - whs_out.record_pointer_list = HDcalloc(whs_out.n_revisions, sizeof(H5FD_onion_record_pointer_t)); - if (NULL == whs_out.record_pointer_list) + history_out.record_locs = HDcalloc(history_out.n_revisions, sizeof(H5FD_onion_record_loc_t)); + if (NULL == history_out.record_locs) TEST_ERROR; - if (H5FD_onion_whole_history_decode(buf, &whs_out) != readsize) + if (H5FD__onion_history_decode(buf, &history_out) != readsize) TEST_ERROR; /* Re-use buffer space to sanity-check checksum for record pointer(s). */ - HDassert(readsize >= sizeof(H5FD_onion_record_pointer_t)); - for (i = 0; i < whs_out.n_revisions; i++) { + HDassert(readsize >= sizeof(H5FD_onion_record_loc_t)); + for (i = 0; i < history_out.n_revisions; i++) { - HDmemcpy(buf, &whs_out.record_pointer_list[i].phys_addr, 8); - HDmemcpy(buf + 8, &whs_out.record_pointer_list[i].record_size, 8); + HDmemcpy(buf, &history_out.record_locs[i].phys_addr, 8); + HDmemcpy(buf + 8, &history_out.record_locs[i].record_size, 8); - if (whs_out.record_pointer_list[i].checksum != H5_checksum_fletcher32(buf, 16)) + if (history_out.record_locs[i].checksum != H5_checksum_fletcher32(buf, 16)) TEST_ERROR; } @@ -1680,9 +1680,9 @@ verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filt /* Ingest revision(s) */ - for (i = 0; i < whs_out.n_revisions; i++) { - H5FD_onion_record_pointer_t *rpp = &whs_out.record_pointer_list[i]; - struct expected_revision * erp = &filter->revisions[i]; + for (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; @@ -1697,7 +1697,7 @@ verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filt TEST_ERROR; /* Initial revision read -- get fixed components */ - readsize = H5FD_onion_revision_record_decode(buf, &rev_out); + readsize = H5FD__onion_revision_record_decode(buf, &rev_out); if (0 == readsize) TEST_ERROR; if (rpp->record_size != readsize) @@ -1723,7 +1723,7 @@ verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filt if (NULL == rev_out.archival_index.list) TEST_ERROR; - readsize = H5FD_onion_revision_record_decode(buf, &rev_out); + readsize = H5FD__onion_revision_record_decode(buf, &rev_out); if (rpp->record_size != readsize) TEST_ERROR; @@ -1747,8 +1747,8 @@ verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filt HDfree(rev_out.archival_index.list); } - HDfree(whs_out.record_pointer_list); - whs_out.record_pointer_list = NULL; + HDfree(history_out.record_locs); + history_out.record_locs = NULL; return 0; @@ -1756,7 +1756,7 @@ error: HDfree(buf); HDfree(rev_out.comment); HDfree(rev_out.archival_index.list); - HDfree(whs_out.record_pointer_list); + HDfree(history_out.record_locs); return -1; @@ -1770,7 +1770,7 @@ error: * + open (not yet written) * + "Empty" .h5 file created * + .onion file created w/ only header (0 whole-hist addr) - * + .onion.recovery created w/ "empty" whole-history + * + .onion.recovery created w/ "empty" history * + Cannot open onionized canonical file (incomplete history, no rev) * * Inspect file contents on backing store. @@ -1789,8 +1789,8 @@ verify_stored_onion_create_0_open(struct onion_filepaths *paths, H5FD_onion_fapl 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 whs_exp_bytes_size = 20; - unsigned char whs_exp_bytes[] = { + 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; @@ -1811,9 +1811,9 @@ verify_stored_onion_create_0_open(struct onion_filepaths *paths, H5FD_onion_fapl UINT32ENCODE(ptr, sum); ptr = NULL; - /* Finish populating expected whole-history bytes */ - sum = H5_checksum_fletcher32(whs_exp_bytes, H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY - 4); - ptr = whs_exp_bytes + H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY - 4; + /* Finish populating expected history bytes */ + sum = H5_checksum_fletcher32(history_exp_bytes, H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY - 4); + ptr = history_exp_bytes + H5FD__ONION_ENCODED_SIZE_WHOLE_HISTORY - 4; UINT32ENCODE(ptr, sum); ptr = NULL; @@ -1847,8 +1847,8 @@ verify_stored_onion_create_0_open(struct onion_filepaths *paths, H5FD_onion_fapl 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 whole-history */ - if (compare_file_bytes_exactly(paths->recovery, fapl_id, whs_exp_bytes_size, whs_exp_bytes) < 0) + /* 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 */ @@ -2213,15 +2213,15 @@ test_several_revisions_with_logical_gaps(void) 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_whole_history_t whs_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) + + 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"); @@ -2230,9 +2230,9 @@ test_several_revisions_with_logical_gaps(void) * SETUP * *********/ - whs_out.version = H5FD__ONION_WHOLE_HISTORY_VERSION_CURR; - whs_out.n_revisions = 0; - whs_out.record_pointer_list = NULL; + history_out.version = H5FD__ONION_WHOLE_HISTORY_VERSION_CURR; + history_out.n_revisions = 0; + history_out.record_locs = NULL; onion_info.backing_fapl_id = h5_fileaccess(); @@ -2516,7 +2516,7 @@ error: onion_filepaths_destroy(paths); } - HDfree(whs_out.record_pointer_list); + HDfree(history_out.record_locs); HDfree(buf); if (file != NULL) @@ -2662,7 +2662,7 @@ test_page_aligned_history_create(void) unsigned char * buf = NULL; struct revise_revision about[2]; H5FD_onion_history_header_t hdr_out; - H5FD_onion_whole_history_t whs_out; + H5FD_onion_history_t history_out; size_t i = 0; uint64_t a_off = b_list_size_s - a_list_size_s; @@ -2672,10 +2672,10 @@ test_page_aligned_history_create(void) * SETUP * *********/ - hdr_out.version = H5FD__ONION_HEADER_VERSION_CURR; - whs_out.version = H5FD__ONION_WHOLE_HISTORY_VERSION_CURR; - whs_out.n_revisions = 0; - whs_out.record_pointer_list = NULL; + hdr_out.version = H5FD__ONION_HEADER_VERSION_CURR; + history_out.version = H5FD__ONION_WHOLE_HISTORY_VERSION_CURR; + history_out.n_revisions = 0; + history_out.record_locs = NULL; onion_info.backing_fapl_id = h5_fileaccess(); fapl_id = H5Pcreate(H5P_FILE_ACCESS); @@ -2760,39 +2760,38 @@ test_page_aligned_history_create(void) TEST_ERROR; if (H5FDread(file, H5FD_MEM_DRAW, H5P_DEFAULT, 0, H5FD__ONION_ENCODED_SIZE_HEADER, buf) < 0) TEST_ERROR; - if (H5FD_onion_history_header_decode(buf, &hdr_out) != H5FD__ONION_ENCODED_SIZE_HEADER) + if (H5FD__onion_history_header_decode(buf, &hdr_out) != H5FD__ONION_ENCODED_SIZE_HEADER) TEST_ERROR; - if (hdr_out.whole_history_addr & ((1 << 5) - 1)) /* 5::PAGE_SIZE_5 */ + if (hdr_out.history_addr & ((1 << 5) - 1)) /* 5::PAGE_SIZE_5 */ TEST_ERROR; HDfree(buf); buf = NULL; - if (NULL == (buf = HDmalloc(hdr_out.whole_history_size))) + if (NULL == (buf = HDmalloc(hdr_out.history_size))) TEST_ERROR; - if (H5FDread(file, H5FD_MEM_DRAW, H5P_DEFAULT, hdr_out.whole_history_addr, hdr_out.whole_history_size, - buf) < 0) + if (H5FDread(file, H5FD_MEM_DRAW, H5P_DEFAULT, hdr_out.history_addr, hdr_out.history_size, buf) < 0) TEST_ERROR; - if (H5FD_onion_whole_history_decode(buf, &whs_out) != hdr_out.whole_history_size) + if (H5FD__onion_history_decode(buf, &history_out) != hdr_out.history_size) TEST_ERROR; - if (whs_out.n_revisions != 2) + if (history_out.n_revisions != 2) TEST_ERROR; - whs_out.record_pointer_list = HDcalloc(whs_out.n_revisions, sizeof(H5FD_onion_record_pointer_t)); - if (NULL == whs_out.record_pointer_list) + history_out.record_locs = HDcalloc(history_out.n_revisions, sizeof(H5FD_onion_record_loc_t)); + if (NULL == history_out.record_locs) TEST_ERROR; - if (H5FD_onion_whole_history_decode(buf, &whs_out) != hdr_out.whole_history_size) + if (H5FD__onion_history_decode(buf, &history_out) != hdr_out.history_size) TEST_ERROR; HDfree(buf); buf = NULL; - for (i = 0; i < whs_out.n_revisions; i++) { - H5FD_onion_record_pointer_t *rr_p = &whs_out.record_pointer_list[i]; - if (rr_p->phys_addr & ((1 << 5) - 1)) /* 5::PAGE_SIZE_5 */ + 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? */ } - HDfree(whs_out.record_pointer_list); - whs_out.record_pointer_list = NULL; + HDfree(history_out.record_locs); + history_out.record_locs = NULL; if (H5FDclose(file) < 0) TEST_ERROR; @@ -2823,7 +2822,7 @@ error: onion_filepaths_destroy(paths); } - HDfree(whs_out.record_pointer_list); + HDfree(history_out.record_locs); HDfree(buf); if (file != NULL) @@ -4631,8 +4630,8 @@ main(void) nerrors -= test_revision_index_to_archival_index(); nerrors -= test_fapl(); nerrors -= test_header_encode_decode(); - nerrors -= test_whole_history_encode_decode_empty(); - nerrors -= test_whole_history_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); |