diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/H5C2.c | 9 | ||||
-rw-r--r-- | src/H5C2journal.c | 2269 | ||||
-rw-r--r-- | src/H5C2pkg.h | 88 | ||||
-rw-r--r-- | src/H5C2private.h | 74 | ||||
-rw-r--r-- | src/H5Fpkg.h | 7 | ||||
-rw-r--r-- | src/H5Fsuper.c | 286 | ||||
-rw-r--r-- | src/H5Ochunk.c | 2 | ||||
-rw-r--r-- | src/H5Omdj_msg.c | 190 | ||||
-rw-r--r-- | src/H5Omessage.c | 15 | ||||
-rw-r--r-- | src/H5Oprivate.h | 38 |
10 files changed, 1507 insertions, 1471 deletions
@@ -656,10 +656,9 @@ H5C2_create(size_t max_cache_size, cache_ptr->trans_api_name[0] = '\0'; cache_ptr->trans_num = 0; cache_ptr->last_trans_on_disk = 0; - cache_ptr->mdj_file_name_ptr = NULL; - cache_ptr->mdj_conf_block_addr = HADDR_UNDEF; - cache_ptr->mdj_conf_block_len = 0; - cache_ptr->mdj_conf_block_ptr = NULL; + cache_ptr->jnl_magic = 0; + cache_ptr->jnl_file_name_len = 0; + (cache_ptr->jnl_file_name)[0] = '\0'; (cache_ptr->mdj_jbrb).magic = H5C2__H5C2_JBRB_T_MAGIC; cache_ptr->tl_len = 0; @@ -712,7 +711,7 @@ H5C2_create(size_t max_cache_size, /* We used to check for journaling here, but the super block hasn't * been read in yet at cache creation time -- thus the check for * journaling has been moved to H5AC2_check_for_journaling(), which - * is simply a * wrapper for H5C2_check_for_journaling(). + * is simply a wrapper for H5C2_check_for_journaling(). * * H5AC2_check_for_journaling() is called at the end of H5Fopen() -- * at which point the superblock has been read. diff --git a/src/H5C2journal.c b/src/H5C2journal.c index ab79a7b..339eb00 100644 --- a/src/H5C2journal.c +++ b/src/H5C2journal.c @@ -97,6 +97,14 @@ static herr_t H5C2_shrink_mdjsc_callback_table(H5C2_t * cache_ptr); * starts, and to call the metadata journaling status * change callbacks after journaling has been started. * + * JRM -- 2/10/09 + * Added journal_magic variable and supporting code. + * + * The idea is to assign a random magic number to both the + * journal file, and to the journal configuration information + * information in the super block so that it will be hard to + * apply the wrong journal file to a corrupted hdf5 file. + * *------------------------------------------------------------------------- */ @@ -108,6 +116,7 @@ H5C2_begin_journaling(H5F_t * f, { herr_t result; herr_t ret_value = SUCCEED; /* Return value */ + int32_t journal_magic; H5C2_mdj_config_t config; FUNC_ENTER_NOAPI(H5C2_begin_journaling, FAIL) @@ -159,11 +168,18 @@ H5C2_begin_journaling(H5F_t * f, HDfprintf(stdout, "%s Finished flushing the cache.\n", FUNC); #endif /* JRM */ + journal_magic = (int32_t)HDrand(); + +#if 0 /* JRM */ + HDfprintf(stdout, "%s journal_magic = %d.\n", FUNC, (int)journal_magic); +#endif /* JRM */ + #if 0 /* JRM */ HDfprintf(stdout, "%s calling H5C2_jb__init().\n", FUNC); #endif /* JRM */ result = H5C2_jb__init(&(cache_ptr->mdj_jbrb), + journal_magic, f->name, config_ptr->journal_file_path, config_ptr->jbrb_buf_size, @@ -185,7 +201,7 @@ H5C2_begin_journaling(H5F_t * f, #endif /* JRM */ /* Note that this call flushes the HDF5 file in passing */ - result = H5C2_mark_journaling_in_progress(f, dxpl_id, + result = H5C2_mark_journaling_in_progress(f, dxpl_id, journal_magic, config_ptr->journal_file_path); if ( result != SUCCEED ) { @@ -373,7 +389,8 @@ H5C2_end_journaling(H5F_t * f, cache_ptr->mdj_enabled = FALSE; /* Remove the journal configuration information from the superblock - * extension. + * extension. In passing, also discard the cache's copies of the + * metadata journaling magic, and the journal file name. */ result = H5C2_unmark_journaling_in_progress(f, dxpl_id, cache_ptr); @@ -411,7 +428,7 @@ H5C2_end_journaling(H5F_t * f, done: #if 0 /* JRM */ - HDfprintf(stdout, "%s: entering.\n", FUNC); + HDfprintf(stdout, "%s: exiting.\n", FUNC); #endif /* JRM */ FUNC_LEAVE_NOAPI(ret_value) @@ -593,7 +610,7 @@ H5C2_get_journal_config(H5C2_t * cache_ptr, config_ptr->enable_journaling = TRUE; HDstrncpy(&(config_ptr->journal_file_path[0]), - cache_ptr->mdj_file_name_ptr, + cache_ptr->jnl_file_name, H5C2__MAX_JOURNAL_FILE_NAME_LEN); config_ptr->journal_file_path[H5C2__MAX_JOURNAL_FILE_NAME_LEN] = '\0'; @@ -1161,7 +1178,7 @@ done: /**************************************************************************/ -/***************** journal config block management code *******************/ +/************* superblock journaling message management code **************/ /**************************************************************************/ /*------------------------------------------------------------------------- @@ -1216,10 +1233,8 @@ H5C2_check_for_journaling(H5F_t * f, HDassert( f ); HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); - HDassert( cache_ptr->mdj_conf_block_addr == HADDR_UNDEF ); - HDassert( cache_ptr->mdj_conf_block_len == 0 ); - HDassert( cache_ptr->mdj_conf_block_ptr == NULL ); - HDassert( cache_ptr->mdj_file_name_ptr == NULL ); + HDassert( cache_ptr->jnl_magic == 0 ); + HDassert( cache_ptr->jnl_file_name_len == 0 ); if ( H5C2__check_for_journaling ) { @@ -1231,8 +1246,8 @@ H5C2_check_for_journaling(H5F_t * f, "H5C2_get_journaling_in_progress() failed.") } - if ( cache_ptr->mdj_file_name_ptr != NULL ) /* journaling was in */ - /* progress */ + if ( cache_ptr->jnl_file_name_len > 0 ) /* journaling was in */ + /* progress */ { #if 0 /* JRM */ HDfprintf(stdout, "%s: journaling was in progress.\n", FUNC); @@ -1240,8 +1255,9 @@ H5C2_check_for_journaling(H5F_t * f, if ( journal_recovered ) { - /* delete the metadata journaling config block and the - * superblock extenstion refering to it. + /* Just forget that we were journaling. Do this by + * deleting the superblock extension message that says + * we were. */ result = H5C2_unmark_journaling_in_progress(f, dxpl_id, cache_ptr); @@ -1261,7 +1277,7 @@ H5C2_check_for_journaling(H5F_t * f, (void)H5Epush2(H5E_DEFAULT, __FILE__, FUNC, __LINE__, H5E_ERR_CLS_g, H5E_CACHE, H5E_CANTJOURNAL, "%s%s%s%s%s%s", l0, l1, l2, l3, - cache_ptr->mdj_file_name_ptr, l4); + cache_ptr->jnl_file_name, l4); (void)H5E_dump_api_stack((int)H5_IS_API(FUNC)); HGOTO_DONE(FAIL) @@ -1285,217 +1301,6 @@ done: /*------------------------------------------------------------------------- - * Function: H5C2_create_journal_config_block() - * - * Purpose: Given a string containing a journal file name and a pointer - * to the associated instance of H5C2_t, allocate a journal - * configuration block, write it to file, and update the - * instance of H5C2_t. - * - * Note that the method assumes that mdj_conf_block_addr is - * NULL on entry. - * - * Return: Success: SUCCEED - * Failure: FAIL - * - * Programmer: John Mainzer - * March 7, 2008 - * - *------------------------------------------------------------------------- - */ - -herr_t -H5C2_create_journal_config_block(const H5F_t * f, - hid_t dxpl_id, - const char * journal_file_name_ptr) -{ - H5C2_t * cache_ptr; - size_t path_len = 0; - hsize_t block_len = 0; - haddr_t block_addr = HADDR_UNDEF; - void * block_ptr = NULL; - uint8_t version = H5C2__JOURNAL_CONF_VERSION; - uint8_t * p = NULL; - char * jfn_ptr = NULL; - uint32_t chksum; - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5C2_create_journal_config_block, FAIL) - - HDassert( f ); - HDassert( f->shared ); - cache_ptr = f->shared->cache2; - HDassert( cache_ptr ); - HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); - - if ( cache_ptr->mdj_conf_block_ptr != NULL ) { - - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "cache_ptr->mdj_conf_block_ptr != NULL on entry?!?") - } - - HDassert( journal_file_name_ptr != NULL ); - - path_len = HDstrlen(journal_file_name_ptr) + 1; - - HDassert( path_len > 0 ); - - block_len = H5C2__JOURNAL_BLOCK_LEN(path_len, f); - - block_ptr = (void *)H5MM_malloc((size_t)block_len); - - if ( block_ptr == NULL ) { - - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ - "allocation of in core journal config block failed."); - } - - p = (uint8_t *)block_ptr; - - /* copy the signature into the config block */ - HDmemcpy(p, H5C2__JOURNAL_CONF_MAGIC, H5C2__JOURNAL_MAGIC_LEN); - p += H5C2__JOURNAL_MAGIC_LEN; - - /* copy the version into the config block */ - HDmemcpy(p, &version, 1); - p++; - - /* copy the length of the journal file path into the config block */ - H5F_ENCODE_LENGTH(f, p, path_len); - - /* copy the path to the journal file into the config block, including - * the terminalting null. Before we do so, make note of p, as its - * value will be the address of our copy of the journal file path. - */ - jfn_ptr = (char *)p; - HDmemcpy(p, journal_file_name_ptr, path_len + 1); - p += path_len + 1; - - HDassert( strcmp(jfn_ptr, journal_file_name_ptr) == 0 ); - - /* compute and save checksum */ - chksum = H5_checksum_metadata(block_ptr, (size_t)(block_len - 4), 0); - UINT32ENCODE(p, chksum); - - HDassert( (unsigned)(p - (uint8_t *)block_ptr) == block_len ); - - - /* having created an in core image of the journaling configuration block, - * we must now allocate space for it in file, and write it to disk. - */ - - block_addr = H5MF_alloc(f, - H5FD_MEM_MDJCONFIG, - dxpl_id, - block_len); - - if ( block_addr == HADDR_UNDEF ) { - - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ - "allocation of file journal config block failed."); - } - - /* now write the block to disk -- note that we don't sync. We will - * have to do that later. - */ - if ( H5F_block_write(f, H5FD_MEM_MDJCONFIG, block_addr, - (size_t)block_len, dxpl_id, block_ptr) < 0 ) - { - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "Can't write metadata journaling config block to file.") - } - - /* finally, if we we get this far, update the cache data structure to - * record the metadata journaling configuration block. - */ - cache_ptr->mdj_file_name_ptr = jfn_ptr; - cache_ptr->mdj_conf_block_addr = block_addr; - cache_ptr->mdj_conf_block_len = block_len; - cache_ptr->mdj_conf_block_ptr = block_ptr; - -done: - - FUNC_LEAVE_NOAPI(ret_value) - -} /* H5AC2__create_journal_config_block() */ - - -/*------------------------------------------------------------------------- - * Function: H5C2_discard_journal_config_block() - * - * Purpose: Free the file and core space allocated to the metadata - * journaling configuration block, and re-set all the associated - * fields in the cache's instance of H5C2_t. - * - * Note that the method assumes that - * - * struct_ptr->mdj_file_name_ptr, - * struct_ptr->mdj_conf_block_addr, - * struct_ptr->mdj_conf_block_len, and - * struct_ptr->mdj_conf_block_ptr - * - * are all set up for the current metadata journaling - * configuration block on entry. On successful exit, these - * fields will all be reset to their initial values. - * - * Return: Success: SUCCEED - * Failure: FAIL - * - * Programmer: John Mainzer - * March 7, 2008 - * - *------------------------------------------------------------------------- - */ - -herr_t -H5C2_discard_journal_config_block(const H5F_t * f, - hid_t dxpl_id) -{ - H5C2_t * cache_ptr; - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5C2_discard_journal_config_block, FAIL) - - HDassert( f ); - HDassert( f->shared ); - cache_ptr = f->shared->cache2; - HDassert( cache_ptr ); - HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); - - if ( ( cache_ptr->mdj_conf_block_addr == HADDR_UNDEF ) || - ( cache_ptr->mdj_conf_block_len == 0 ) || - ( cache_ptr->mdj_conf_block_ptr == NULL ) || - ( cache_ptr->mdj_file_name_ptr == NULL ) ) { - - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "metadata journaling config block undefined on entry?!?") - } - - if ( H5MF_xfree(f, H5FD_MEM_MDJCONFIG, dxpl_id, - cache_ptr->mdj_conf_block_addr, - cache_ptr->mdj_conf_block_len) < 0 ) { - - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ - "deallocation of file journal config block failed."); - } - - H5MM_xfree(cache_ptr->mdj_conf_block_ptr); - - /* if we get this far, go ahead and null out the fields in *cache_ptr */ - - cache_ptr->mdj_conf_block_addr = HADDR_UNDEF; - cache_ptr->mdj_conf_block_len = 0; - cache_ptr->mdj_conf_block_ptr = NULL; - cache_ptr->mdj_file_name_ptr = NULL; - -done: - - FUNC_LEAVE_NOAPI(ret_value) - -} /* H5AC2_discard_journal_config_block() */ - - -/*------------------------------------------------------------------------- * Function: H5C2_get_journaling_in_progress() * * Purpose: Query the HDF5 file to see if it is marked as having @@ -1524,6 +1329,13 @@ done: * Programmer: John Mainzer * March 11, 2008 * + * Changes: JRM -- 2/20/09 + * Reworked to reflect the move of the journal file name + * and magic from the journaling configuration block to + * the metadata journaling superblock extension message. + * Note that the journaling configuration block no longer + * exists. + * *------------------------------------------------------------------------- */ @@ -1532,7 +1344,6 @@ H5C2_get_journaling_in_progress(const H5F_t * f, hid_t dxpl_id, H5C2_t * cache_ptr) { - herr_t result; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5C2_get_journaling_in_progress, FAIL) @@ -1545,31 +1356,42 @@ H5C2_get_journaling_in_progress(const H5F_t * f, HDassert( f->shared != NULL ); HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); - HDassert( cache_ptr->mdj_conf_block_addr == HADDR_UNDEF ); - HDassert( cache_ptr->mdj_conf_block_len == 0 ); - HDassert( cache_ptr->mdj_conf_block_ptr == NULL ); - HDassert( cache_ptr->mdj_file_name_ptr == NULL ); + HDassert( cache_ptr->jnl_file_name_len == 0 ); #if 0 /* JRM */ - HDfprintf(stdout, "%s: f->shared->mdc_jrnl_enabled = %d.\n", FUNC, - (int)(f->shared->mdc_jrnl_enabled)); + HDfprintf(stdout, "%s: f->shared->mdc_jnl_enabled = %d.\n", FUNC, + (int)(f->shared->mdc_jnl_enabled)); #endif /* JRM */ - if ( f->shared->mdc_jrnl_enabled == TRUE ) { + if ( f->shared->mdc_jnl_enabled == TRUE ) { - cache_ptr->mdj_conf_block_addr = f->shared->mdc_jrnl_block_loc; - cache_ptr->mdj_conf_block_len = f->shared->mdc_jrnl_block_len; - - result = H5C2_load_journal_config_block(f, - dxpl_id, - cache_ptr, - cache_ptr->mdj_conf_block_addr, - cache_ptr->mdj_conf_block_len); - if ( result != SUCCEED ) { + if ( f->shared->mdc_jnl_file_name_len <= 0 ) { HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_load_journal_config_block() failed.") - } + "journaling enabled but jnl file name empty?!?.") + } + + if ( f->shared->mdc_jnl_file_name_len > + H5C2__MAX_JOURNAL_FILE_NAME_LEN ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "journal file name too long?!?.") + } + + cache_ptr->jnl_magic = f->shared->mdc_jnl_magic; + cache_ptr->jnl_file_name_len = f->shared->mdc_jnl_file_name_len; + HDstrncpy(cache_ptr->jnl_file_name, + f->shared->mdc_jnl_file_name, + f->shared->mdc_jnl_file_name_len + 1); + + if ( ( (cache_ptr->jnl_file_name)[cache_ptr->jnl_file_name_len] + != '\0' ) || + ( strlen(cache_ptr->jnl_file_name) != + (size_t)(cache_ptr->jnl_file_name_len) ) ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "bad jnl file name or name len?!?.") + } } #if 0 /* JRM */ @@ -1588,140 +1410,6 @@ done: /*------------------------------------------------------------------------- - * Function: H5C2_load_journal_config_block() - * - * Purpose: Given the base address and lenght of a journal configuration - * block, attempt to load it, and store it in the cache structure. - * - * Note that the method assumes that mdj_conf_block_addr is - * NULL on entry. - * - * Return: Success: SUCCEED - * Failure: FAIL - * - * Programmer: John Mainzer - * March 11, 2008 - * - *------------------------------------------------------------------------- - */ - -herr_t -H5C2_load_journal_config_block(const H5F_t * f, - hid_t dxpl_id, - H5C2_t * cache_ptr, - haddr_t block_addr, - hsize_t block_len) -{ - size_t path_len = 0; - void * block_ptr = NULL; - uint8_t version; - uint8_t * p = NULL; - char * jfn_ptr = NULL; - uint32_t computed_chksum; - uint32_t read_chksum; - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5C2_load_journal_config_block, FAIL) - - HDassert( f ); - HDassert( f->shared ); - HDassert( cache_ptr ); - HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); - - if ( cache_ptr->mdj_conf_block_ptr != NULL ) { - - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "cache_ptr->mdj_conf_block_ptr != NULL on entry?!?") - } - - block_ptr = (void *)H5MM_malloc((size_t)block_len); - - if ( block_ptr == NULL ) { - - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ - "allocation of in core journal config block failed."); - } - - p = (uint8_t *)block_ptr; - - /* read the metadata journaling block from file */ - if ( H5F_block_read(f, H5FD_MEM_MDJCONFIG, block_addr, - (size_t)block_len, dxpl_id, block_ptr) < 0 ) { - -#if 0 /* JRM */ - HDfprintf(stdout, "%s: block_addr = %lld, block_len = %lld.\n", - FUNC, (long long)block_addr, (long long)block_len); -#endif /* JRM */ - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "Can't read metadata journaling configuration block.") - } - - /* verify the signature */ - if ( HDmemcmp(p, H5C2__JOURNAL_CONF_MAGIC, H5C2__JOURNAL_MAGIC_LEN) != 0 ) { - - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "Bad signature on metadata journaling configuration block.") - } - p += H5C2__JOURNAL_MAGIC_LEN; - - /* get the version of the config block */ - version = *p++; - - if ( version != H5C2__JOURNAL_CONF_VERSION ) { - - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "Bad version on metadata journaling configuration block.") - } - - /* get the length of the journal file path into the config block */ - H5F_DECODE_LENGTH(f, p, path_len); - - /* Verify that the length matches the actual path length. Also, - * make note of p, as its value will be the address of our copy of - * the journal file path. - */ - jfn_ptr = (char *)p; - if ( HDstrlen(jfn_ptr) != path_len - 1 ) { - - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "Bad path_len in metadata journaling configuration block.") - } - - p += path_len + 1; - - /* get the checksum from the block */ - UINT32DECODE(p, read_chksum); - - /* compute the actual checksum */ - computed_chksum = - H5_checksum_metadata(block_ptr, (size_t)(block_len - 4), 0); - - /* verify that the computed and read checksums match */ - if ( computed_chksum != read_chksum ) { - - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "Bad checksum in metadata journaling configuration block.") - } - - HDassert( (unsigned)(p - (uint8_t *)block_ptr) == block_len ); - - /* finally, if we we get this far, we have read the metadata journaling - * configuration block successfully. Record the data in the cache - * structure. - */ - cache_ptr->mdj_file_name_ptr = jfn_ptr; - cache_ptr->mdj_conf_block_addr = block_addr; - cache_ptr->mdj_conf_block_len = block_len; - cache_ptr->mdj_conf_block_ptr = block_ptr; - -done: - - FUNC_LEAVE_NOAPI(ret_value) - -} /* H5C2_load_journal_config_block() */ - - -/*------------------------------------------------------------------------- * Function: H5C2_mark_journaling_in_progress() * * Purpose: Modify the HDF5 file to indicate that journaling is @@ -1740,12 +1428,22 @@ done: * Programmer: John Mainzer * March 11, 2008 * + * Changes: JRM -- 2/10/09 + * Added the journal_magic parameter and related code. + * + * JRM -- 2/20/09 + * Reworked function to reflect the move of the journal + * file name and magic to the super block extension message + * and out of the metadata journaling configuration block + * which no longer exists. + * *------------------------------------------------------------------------- */ herr_t H5C2_mark_journaling_in_progress(H5F_t * f, hid_t dxpl_id, + const int32_t journal_magic, const char * journal_file_name_ptr) { H5C2_t * cache_ptr; @@ -1758,16 +1456,13 @@ H5C2_mark_journaling_in_progress(H5F_t * f, #endif /* JRM */ HDassert( f != NULL ); HDassert( f->shared != NULL ); - HDassert( ! f->shared->mdc_jrnl_enabled ); + HDassert( ! f->shared->mdc_jnl_enabled ); cache_ptr = f->shared->cache2; HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); - HDassert( cache_ptr->mdj_conf_block_addr == HADDR_UNDEF ); - HDassert( cache_ptr->mdj_conf_block_len == 0 ); - HDassert( cache_ptr->mdj_conf_block_ptr == NULL ); - HDassert( cache_ptr->mdj_file_name_ptr == NULL ); + HDassert( cache_ptr->jnl_file_name_len == 0 ); HDassert( journal_file_name_ptr != NULL ); /* Can't journal a read only file, so verify that we are @@ -1779,32 +1474,35 @@ H5C2_mark_journaling_in_progress(H5F_t * f, "File is opened read only.") } - /* first, create a metadata journaling configuration block */ -#if 0 /* JRM */ - HDfprintf(stdout, "%s: creating mdj config block.\n", FUNC); -#endif /* JRM */ - result = H5C2_create_journal_config_block(f, - dxpl_id, - journal_file_name_ptr); + cache_ptr->jnl_magic = journal_magic; + cache_ptr->jnl_file_name_len = strlen(journal_file_name_ptr); - if ( result != SUCCEED ) { + if ( cache_ptr->jnl_file_name_len <= 0 ) { HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_create_journal_config_block() failed.") + "length of journal file name is zero.") } - HDassert( cache_ptr->mdj_conf_block_addr != HADDR_UNDEF ); - HDassert( cache_ptr->mdj_conf_block_len != 0 ); - HDassert( cache_ptr->mdj_conf_block_ptr != NULL ); - HDassert( cache_ptr->mdj_file_name_ptr != NULL ); + if ( cache_ptr->jnl_file_name_len > H5C2__MAX_JOURNAL_FILE_NAME_LEN ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "journal file name too long.") + } - /* now, load the base addr and length of the configuration block - * into shared, and then call H5F_super_write_mdj_msg() to write - * the metadata journaling superblock extension message to file. + HDstrncpy(cache_ptr->jnl_file_name, + journal_file_name_ptr, + (size_t)(cache_ptr->jnl_file_name_len + 1)); + + /* now, load the journaling information into shared, and then call + * H5F_super_write_mdj_msg() to write the metadata journaling + * superblock extension message to file. */ - f->shared->mdc_jrnl_enabled = TRUE; - f->shared->mdc_jrnl_block_loc = cache_ptr->mdj_conf_block_addr; - f->shared->mdc_jrnl_block_len = cache_ptr->mdj_conf_block_len; + f->shared->mdc_jnl_enabled = TRUE; + f->shared->mdc_jnl_magic = journal_magic; + f->shared->mdc_jnl_file_name_len = (size_t)(cache_ptr->jnl_file_name_len); + HDstrncpy(f->shared->mdc_jnl_file_name, + journal_file_name_ptr, + (size_t)(cache_ptr->jnl_file_name_len + 1)); #if 0 /* JRM */ HDfprintf(stdout, "%s: writing superblock extension.\n", FUNC); @@ -1868,6 +1566,13 @@ done: * Programmer: John Mainzer * March 11, 2008 * + * Changes: JRM -- 2/20/09 + * Reworked function to reflect the move of the journal + * file name and magic from the metadata journaling config + * block and into a superblock extension message. Note that + * the metadata journaling configuration block no longer + * exists. + * *------------------------------------------------------------------------- */ @@ -1890,18 +1595,11 @@ H5C2_unmark_journaling_in_progress(H5F_t * f, #endif /* JRM */ HDassert( f != NULL ); HDassert( f->shared != NULL ); - HDassert( f->shared->mdc_jrnl_enabled ); + HDassert( f->shared->mdc_jnl_enabled ); HDassert( f->shared->cache2 == cache_ptr ); HDassert( cache_ptr ); HDassert( cache_ptr->magic == H5C2__H5C2_T_MAGIC ); - HDassert( cache_ptr->mdj_conf_block_addr != HADDR_UNDEF ); - HDassert( cache_ptr->mdj_conf_block_len > 0 ); - HDassert( cache_ptr->mdj_conf_block_ptr != NULL ); - HDassert( cache_ptr->mdj_file_name_ptr != NULL ); - HDassert( f->shared->mdc_jrnl_block_loc == - cache_ptr->mdj_conf_block_addr ); - HDassert( f->shared->mdc_jrnl_block_len == - cache_ptr->mdj_conf_block_len ); + HDassert( cache_ptr->jnl_file_name_len > 0 ); /* Can't journal a read only file, so verify that we are @@ -1913,27 +1611,19 @@ H5C2_unmark_journaling_in_progress(H5F_t * f, "File is opened read only.") } - /* next, discard the metadata journaling configuration block */ - result = H5C2_discard_journal_config_block(f, dxpl_id); - - if ( result != SUCCEED ) { - - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_discard_journal_config_block() failed.") - } - - HDassert( cache_ptr->mdj_conf_block_addr == HADDR_UNDEF ); - HDassert( cache_ptr->mdj_conf_block_len == 0 ); - HDassert( cache_ptr->mdj_conf_block_ptr == NULL ); - HDassert( cache_ptr->mdj_file_name_ptr == NULL ); + /* Discard the journal file name and magic in *cache_ptr */ + cache_ptr->jnl_magic = 0; + cache_ptr->jnl_file_name_len = 0; + (cache_ptr->jnl_file_name)[0] = '\0'; /* now, mark f->shared to indicate that journaling is not in * progress, and then call H5F_super_write_mdj_msg() to write * the changes to disk. */ - f->shared->mdc_jrnl_enabled = FALSE; - f->shared->mdc_jrnl_block_loc = HADDR_UNDEF; - f->shared->mdc_jrnl_block_len = 0; + f->shared->mdc_jnl_enabled = FALSE; + f->shared->mdc_jnl_magic = 0; + f->shared->mdc_jnl_file_name_len = 0; + (f->shared->mdc_jnl_file_name)[0] = '\0'; if ( H5F_super_write_mdj_msg(f, dxpl_id) < 0 ) { @@ -2655,134 +2345,277 @@ done: } /* H5C2_shrink_mdjsc_callback_table() */ - + /**************************************************************************/ /********************** journal file management code **********************/ /**************************************************************************/ /****************************************************************************** * - * Function: H5C2_jb__flush_full_buffers + * Function: H5C2_jb__bin2hex + * + * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> + * Tuesday, March 4, 2008 + * + * Purpose: Convert binary data into hexadecimal. + * + * Returns: SUCCEED on success. + * + ******************************************************************************/ + +herr_t +H5C2_jb__bin2hex(const uint8_t * buf, + char * hexdata, + size_t * hexlength, + size_t buf_size) + +{ + size_t v; /* Local index variable */ + uint8_t c; + char * t; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5C2_jb__bin2hex) + + t = hexdata; + t[0] = ' '; + for (v = 0; v < buf_size; v++) { + + t = &hexdata[v * 3 + 1]; + c = buf[v]; + HDsnprintf(t, (size_t)3, "%02x ", c); + t[2] = ' '; + + } /* end for */ + t[3] = '\n'; + t[4] = 0; + + * hexlength = v * 3 + 2; + + FUNC_LEAVE_NOAPI(SUCCEED) + +} /* end H5C2_jb__bin2hex*/ + + +/****************************************************************************** + * + * Function: H5C2_jb__comment * * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> * Wednesday, February 6, 2008 * - * Purpose: Flush all the dirtied buffers in the ring buffer - * starting with the buffer referenced by struct_ptr->get - * and ending with the buffer right before the one - * referenced by struct_ptr->put. + * Purpose: Insert the supplied comment in the journal file. This + * call may be ignored if the journal file is machine + * readable. * * Returns: SUCCEED on success. * ******************************************************************************/ herr_t -H5C2_jb__flush_full_buffers(H5C2_jbrb_t * struct_ptr) +H5C2_jb__comment(H5C2_jbrb_t * struct_ptr, + const char * comment_ptr) { - hbool_t verbose = FALSE; - int result; + char * temp = NULL; + size_t temp_len; herr_t ret_value = SUCCEED; - FUNC_ENTER_NOAPI(H5C2_jb__flush_full_buffers, FAIL) - - if ( verbose ) { HDfprintf(stdout, "%s: entering.\n", FUNC); } + FUNC_ENTER_NOAPI(H5C2_jb__comment, FAIL) - /* this asserts that at least one buffer is in use */ - HDassert(struct_ptr->bufs_in_use > 0); - /* write an assert to verify that at least one buffer is full */ - HDassert( (struct_ptr->put != struct_ptr->get) || - (struct_ptr->rb_free_space == 0) ); - - /* flush all full, dirtied journal buffers to disk */ - if (struct_ptr->get < struct_ptr->put) { + /* Check Arguments */ + HDassert(struct_ptr); + HDassert(comment_ptr); + HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); + HDassert(struct_ptr->hdf5_file_name); - /* can write solid chunk from get up to, but not - * including, put - */ - result = HDwrite(struct_ptr->journal_file_fd, - (*struct_ptr->buf)[struct_ptr->get], - (struct_ptr->put - struct_ptr->get) * struct_ptr->buf_size); + /* Verify that header message is present in journal file or ring buffer. + * If not, write it. + */ + if ( struct_ptr->header_present == FALSE ) { - if ( result == -1 ) { + if ( H5C2_jb__write_header_entry(struct_ptr) != SUCCEED ) { - if ( verbose ) { HDfprintf(stdout, "%s: write failed 1.\n", FUNC); } - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, \ - "Journal file write failed (1).") + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__write_header_entry() failed.\n") } - struct_ptr->bufs_in_use -= (struct_ptr->put - struct_ptr->get); - struct_ptr->rb_free_space += (struct_ptr->put - struct_ptr->get) * struct_ptr->buf_size; + } /* end if */ + + temp_len = HDstrlen(comment_ptr) + 11; + if ( ( temp = H5MM_malloc(HDstrlen(comment_ptr) + 11) ) == NULL ) { + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "allocation of temp buffer failed."); } /* end if */ - else { + /* Write comment message */ + HDsnprintf(temp, temp_len, "C comment %s", comment_ptr); - /* write from get through end of buffer */ - result = HDwrite(struct_ptr->journal_file_fd, - (*struct_ptr->buf)[struct_ptr->get], - (struct_ptr->num_bufs - struct_ptr->get) * struct_ptr->buf_size); + if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(temp), temp, FALSE, struct_ptr->cur_trans ) < 0 ) { - if ( result == -1 ) { + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__write_to_buffer() failed.\n") + } /* end if */ - if ( verbose ) { HDfprintf(stdout, "%s: write failed 2.\n", FUNC); } - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, \ - "Journal file write failed (2).") - } + if ( H5C2_jb__write_to_buffer(struct_ptr, 1, "\n", FALSE, struct_ptr->cur_trans ) < 0 ) { - struct_ptr->bufs_in_use -= (struct_ptr->num_bufs - struct_ptr->get); - struct_ptr->rb_free_space += (struct_ptr->num_bufs - struct_ptr->get) * struct_ptr->buf_size; + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__write_to_buffer() failed.\n") + } /* end if */ - /* if put = 0, then everything that needs to be flushed will have been - flushed, so we can stop here. Otherwise, need to flush all buffers - from the start of the ring buffer's allocated space up to, but not - including, the buffer indexed by put. */ - if (struct_ptr->put != 0) { +done: - result = HDwrite(struct_ptr->journal_file_fd, - (*struct_ptr->buf)[0], - (struct_ptr->put) * struct_ptr->buf_size); + if ( temp != NULL ) { - if ( result == -1 ) { + temp = H5MM_xfree(temp); + if ( temp != NULL ) { - if ( verbose ) { - HDfprintf(stdout, "%s: write failed 3.\n", FUNC); - } - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, \ - "Journal file write failed(3).") - } /* end if */ + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "free of assembly buffer failed."); + } + } - struct_ptr->rb_free_space += (struct_ptr->put * struct_ptr->buf_size); + FUNC_LEAVE_NOAPI(ret_value) - } /* end if */ +} /* end H5C2_jb__comment */ - struct_ptr->bufs_in_use -= struct_ptr->put; + +/***************************************************************************** + * + * Function: H5C2_jb__end_transaction + * + * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> + * Wednesday, February 6, 2008 + * + * Purpose: Verify that the supplied transaction is in progress, + * and that at least one journal entry has been written + * under it. Then construct an end transaction message, + * and write it to the current journal buffer. Make note + * that the supplied transaction is closed, and that no + * transaction is in progress. + * + * Returns: SUCCEED on success. + * + *****************************************************************************/ +herr_t +H5C2_jb__end_transaction(H5C2_jbrb_t * struct_ptr, + uint64_t trans_num) +{ + char temp[25]; + herr_t ret_value = SUCCEED; - } /* end else */ + FUNC_ENTER_NOAPI(H5C2_jb__end_transaction, FAIL) +#if 0 /* JRM */ + HDfprintf(stdout, "%s trans_num = %lld.\n", FUNC, trans_num); +#endif /* JRM */ + /* Check Arguments */ + HDassert(struct_ptr); + HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); - HDassert(struct_ptr->bufs_in_use <= 1); + /* Verify that the supplied transaction is in progress */ + if ( ( struct_ptr->trans_in_prog != TRUE ) || + ( struct_ptr->cur_trans != trans_num ) ) { - /* update get index */ - struct_ptr->get = struct_ptr->put; + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Transaction not in progress or bad transaction number.") + } /* end if */ - /* record last transaction number that made it to disk */ - if (struct_ptr->put == 0) { + /* Verify that at least one journal entry has been written under + * the current transaction + */ + if ( struct_ptr->jentry_written != TRUE ) { - struct_ptr->last_trans_on_disk = - (*struct_ptr->trans_tracking)[struct_ptr->num_bufs - 1]; + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Empty transaction -- at least one journal entry required.") + } /* end if */ - } else { - struct_ptr->last_trans_on_disk = - (*struct_ptr->trans_tracking)[struct_ptr->put - 1]; - } + /* Prepare end transaction message */ + HDsnprintf(temp, (size_t)25, "3 end_trans %llu\n", trans_num); + + /* Write end transaction message */ + if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(temp), temp, + TRUE, trans_num ) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__write_to_buffer() failed.\n") + } /* end if */ + + /* reset boolean flag indicating if at least one journal entry has + * been written under transaction + */ + struct_ptr->jentry_written = FALSE; + + /* Close current transaction */ + struct_ptr->trans_in_prog = FALSE; done: + + FUNC_LEAVE_NOAPI(ret_value) - if ( verbose ) { HDfprintf(stdout, "%s: exiting.\n", FUNC); } +} /* end H5C2_jb__end_transaction */ + + +/****************************************************************************** + * + * Function: H5C2_jb__eoa + * + * Programmer: Mike McGreevy <mamcgree@hdfgroup.org> + * July 29, 2008 + * + * Purpose: Insert the supplied EOA into the journal file. + * + * Returns: SUCCEED on success. + * + ******************************************************************************/ + +herr_t +H5C2_jb__eoa(H5C2_jbrb_t * struct_ptr, + haddr_t eoa) +{ + char temp[40]; + size_t temp_len = 40; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5C2_jb__eoa, FAIL) + + /* Check Arguments */ + HDassert(struct_ptr); + HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); + HDassert(struct_ptr->hdf5_file_name); + + /* Verify that header message is present in journal file or ring buffer. + * If not, write it. + */ + if ( struct_ptr->header_present == FALSE ) { + + if ( H5C2_jb__write_header_entry(struct_ptr) != SUCCEED ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__write_header_entry() failed.\n") + } + } /* end if */ + + /* Write EOA message */ + HDsnprintf(temp, temp_len, "E eoa_value 0x%llx", eoa); + + if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(temp), temp, FALSE, struct_ptr->cur_trans ) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__write_to_buffer() failed.\n") + } /* end if */ + + if ( H5C2_jb__write_to_buffer(struct_ptr, 1, "\n", FALSE, + struct_ptr->cur_trans ) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__write_to_buffer() failed.\n") + } /* end if */ + +done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5C2_jb__flush_full_buffers */ +} /* end H5C2_jb__eoa */ /****************************************************************************** @@ -2934,279 +2767,188 @@ done: /****************************************************************************** * - * Function: H5C2_jb__write_to_buffer + * Function: H5C2_jb__flush_full_buffers * * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> * Wednesday, February 6, 2008 * - * Purpose: Put the contents of data into the journal buffers. This - * is done as follows: While the data to be written is - * larger than the amount of space left in the ring buffer, - * the ring buffer is filled to capacity with data and - * flushed. This repeats until the unwritten data remaining - * can fit in the ring buffer without having to loop around - * to the top. - * - * At this point, the rest of the data can just be written - * without having to break it up further. In the event - * the data covers more than one journal buffer, the get - * and put indices are updated to state this fact. Any - * journal buffers that were filled during the write are - * flushed. + * Purpose: Flush all the dirtied buffers in the ring buffer + * starting with the buffer referenced by struct_ptr->get + * and ending with the buffer right before the one + * referenced by struct_ptr->put. * * Returns: SUCCEED on success. * ******************************************************************************/ herr_t -H5C2_jb__write_to_buffer(H5C2_jbrb_t * struct_ptr, - size_t size, - const char * data, - hbool_t is_end_trans, - uint64_t trans_num) +H5C2_jb__flush_full_buffers(H5C2_jbrb_t * struct_ptr) { + hbool_t verbose = FALSE; + int result; herr_t ret_value = SUCCEED; - unsigned long track_last_trans = 0; - int oldput = 0; - int i; - - FUNC_ENTER_NOAPI(H5C2_jb__write_to_buffer, FAIL) - /* Check Arguments */ - HDassert(struct_ptr); - HDassert(data); - HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); - HDassert(HDstrlen(data) == size); - HDassert(struct_ptr->rb_space_to_rollover <= - struct_ptr->num_bufs * struct_ptr->buf_size); - HDassert(struct_ptr->rb_space_to_rollover > 0); - - /* If the data size exceeds the bounds of the ring buffer's allocated - * memory, loop around to top - */ - if (size >= struct_ptr->rb_space_to_rollover) { - - while (size >= struct_ptr->rb_space_to_rollover) { - - /* Assertions */ - HDassert(size != 0); - HDassert(HDstrlen(data) >= struct_ptr->rb_space_to_rollover); - - /* fill up remaining space in the ring buffer */ - HDmemcpy(struct_ptr->head, data, struct_ptr->rb_space_to_rollover); - - /* move head to point to start of ring buffer */ - struct_ptr->head = (*struct_ptr->buf)[0]; - - /* make note of last transaction on disk */ - track_last_trans = (*struct_ptr->trans_tracking)[struct_ptr->put]; - - /* update rb_free_space */ - struct_ptr->rb_free_space -= struct_ptr->rb_space_to_rollover; - - /* Fill out the remainder of the trans_tracking array with - the most recent transaction in the array.*/ - (*struct_ptr->trans_tracking)[0] = track_last_trans; - for (i=struct_ptr->put; i<struct_ptr->num_bufs; i++) - { - (*struct_ptr->trans_tracking)[i] = track_last_trans; - } - - /* reset put index */ - struct_ptr->put = 0; - - /* update bufs_in_use as necessary */ - struct_ptr->bufs_in_use = struct_ptr->num_bufs - struct_ptr->get; - - /* check to see if trans_tracking needs to be updated. If so, - then update it */ - if ((size == struct_ptr->rb_space_to_rollover) && - (is_end_trans == TRUE)) { - - (*struct_ptr->trans_tracking)[struct_ptr->num_bufs - 1] - = trans_num; - (*struct_ptr->trans_tracking)[0] = trans_num; - } - - /* flush buffers */ - if ( H5C2_jb__flush_full_buffers(struct_ptr) < 0 ) { - - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_jb__flush_full_buffers() failed.\n") - } - - /* update remaining size of data to be written */ - size = size - struct_ptr->rb_space_to_rollover; - - /* update the data pointer to point to the remaining data to be - * written - */ - data = &data[struct_ptr->rb_space_to_rollover]; - - /* update the amount of space left at end of ring buffer */ - struct_ptr->rb_space_to_rollover = - struct_ptr->buf_size * struct_ptr->num_bufs; - - /* update the amount of space in the current buffer */ - struct_ptr->cur_buf_free_space = struct_ptr->buf_size; + FUNC_ENTER_NOAPI(H5C2_jb__flush_full_buffers, FAIL) - } /* end while */ - } /* end if */ + if ( verbose ) { HDfprintf(stdout, "%s: entering.\n", FUNC); } - /* If the size of the data exceeds the bounds of a single journal - * buffer, will write into multiple - */ - if (size > struct_ptr->cur_buf_free_space) { + /* this asserts that at least one buffer is in use */ + HDassert(struct_ptr->bufs_in_use > 0); + /* write an assert to verify that at least one buffer is full */ + HDassert( (struct_ptr->put != struct_ptr->get) || + (struct_ptr->rb_free_space == 0) ); - HDassert(struct_ptr->cur_buf_free_space != 0); + /* flush all full, dirtied journal buffers to disk */ + if (struct_ptr->get < struct_ptr->put) { - /* write data into journal buffers */ - HDmemcpy(struct_ptr->head, data, size); + /* can write solid chunk from get up to, but not + * including, put + */ + result = HDwrite(struct_ptr->journal_file_fd, + (*struct_ptr->buf)[struct_ptr->get], + (struct_ptr->put - struct_ptr->get) * + struct_ptr->buf_size); - /* update head pointer */ - struct_ptr->head = &struct_ptr->head[size]; + if ( result == -1 ) { - /* make note of last transaction on disk */ - track_last_trans = (*struct_ptr->trans_tracking)[struct_ptr->put]; - oldput = struct_ptr->put; + if ( verbose ) { HDfprintf(stdout, "%s: write failed 1.\n", FUNC); } + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, \ + "Journal file write failed (1).") + } - /* update rb_free_space */ - struct_ptr->rb_free_space -= size; + struct_ptr->bufs_in_use -= (struct_ptr->put - struct_ptr->get); + struct_ptr->rb_free_space += (struct_ptr->put - struct_ptr->get) * struct_ptr->buf_size; - /* update put index */ - struct_ptr->put += - (size-struct_ptr->cur_buf_free_space)/(struct_ptr->buf_size) + 1; + } /* end if */ - /* Drag the last transaction in a filled buffer value residing in the - old put location through the trans_tracking array to the new - corresponding put position. */ - for (i=oldput; i<struct_ptr->put+1; i++) - { - (*struct_ptr->trans_tracking)[i] = track_last_trans; - } + else { - /* update current buffer usage */ - struct_ptr->cur_buf_free_space = - struct_ptr->rb_space_to_rollover - size - - (struct_ptr->num_bufs - (struct_ptr->put + 1)) * - (struct_ptr->buf_size ); + /* write from get through end of buffer */ + result = HDwrite(struct_ptr->journal_file_fd, + (*struct_ptr->buf)[struct_ptr->get], + (struct_ptr->num_bufs - struct_ptr->get) * struct_ptr->buf_size); - /* update bufs_in_use as necessary */ - struct_ptr->bufs_in_use = struct_ptr->put - struct_ptr->get; - if (struct_ptr->cur_buf_free_space < struct_ptr->buf_size) { + if ( result == -1 ) { - struct_ptr->bufs_in_use++; + if ( verbose ) { HDfprintf(stdout, "%s: write failed 2.\n", FUNC); } + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, \ + "Journal file write failed (2).") } - /* check to see if trans_tracking needs to be updated. If so, - then update it */ - if (is_end_trans == TRUE) { - - if (struct_ptr->cur_buf_free_space == struct_ptr->buf_size) { - (*struct_ptr->trans_tracking)[struct_ptr->put - 1] = trans_num; - } - else { - (*struct_ptr->trans_tracking)[struct_ptr->put] = trans_num; - } - - } /* end if */ + struct_ptr->bufs_in_use -= (struct_ptr->num_bufs - struct_ptr->get); + struct_ptr->rb_free_space += (struct_ptr->num_bufs - struct_ptr->get) * + struct_ptr->buf_size; - /* flush buffers */ - if ( H5C2_jb__flush_full_buffers(struct_ptr) < 0 ) { + /* if put = 0, then everything that needs to be flushed will have been + * flushed, so we can stop here. Otherwise, need to flush all buffers + * from the start of the ring buffer's allocated space up to, but not + * including, the buffer indexed by put. + */ + if (struct_ptr->put != 0) { - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_jb__flush_full_buffers() failed.\n") - } + result = HDwrite(struct_ptr->journal_file_fd, + (*struct_ptr->buf)[0], + (struct_ptr->put) * struct_ptr->buf_size); - /* update space left at end of ring buffer */ - struct_ptr->rb_space_to_rollover -= size; + if ( result == -1 ) { - } /* end if */ + if ( verbose ) { + HDfprintf(stdout, "%s: write failed 3.\n", FUNC); + } + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, \ + "Journal file write failed(3).") + } /* end if */ - /* if the data can fit in the remaining space in the current journal - * buffer indexed by put - */ - else if (size > 0) { + struct_ptr->rb_free_space += (struct_ptr->put * struct_ptr->buf_size); - HDassert(size <= struct_ptr->cur_buf_free_space); - - /* write data into journal buffer */ - HDmemcpy(struct_ptr->head, data, size); + } /* end if */ - /* increment bufs_in_use as necessary */ - if ( ( struct_ptr->bufs_in_use == 0 ) ) { + struct_ptr->bufs_in_use -= struct_ptr->put; - struct_ptr->bufs_in_use++; - } + } /* end else */ + + HDassert(struct_ptr->bufs_in_use <= 1); - /* update head pointer */ - struct_ptr->head = &struct_ptr->head[size]; + /* update get index */ + struct_ptr->get = struct_ptr->put; + + /* record last transaction number that made it to disk */ + if (struct_ptr->put == 0) { - /* update rb_free_space */ - struct_ptr->rb_free_space -= size; + struct_ptr->last_trans_on_disk = + (*struct_ptr->trans_tracking)[struct_ptr->num_bufs - 1]; - /* update current buffer usage */ - struct_ptr->cur_buf_free_space -= size; + } else { - /* update end of buffer space */ - struct_ptr->rb_space_to_rollover -= size; - - /* check to see if trans_tracking needs to be updated. If so, - then update it */ - if (is_end_trans == TRUE) { - - (*struct_ptr->trans_tracking)[struct_ptr->put] - = trans_num; - } /* end if */ + struct_ptr->last_trans_on_disk = + (*struct_ptr->trans_tracking)[struct_ptr->put - 1]; + } - /* if buffer is full, flush it, and loop to the top of the - * ring buffer if at the end. - */ - if (struct_ptr->cur_buf_free_space == 0) { +done: - if ( struct_ptr->put != (struct_ptr->num_bufs - 1) ) { - struct_ptr->put += 1; + if ( verbose ) { HDfprintf(stdout, "%s: exiting.\n", FUNC); } - /* Drag trans_tracking value into next buffer */ - (*struct_ptr->trans_tracking)[struct_ptr->put] - = (*struct_ptr->trans_tracking)[struct_ptr->put - 1]; + FUNC_LEAVE_NOAPI(ret_value) - } /* end if */ - - else { +} /* end H5C2_jb__flush_full_buffers */ - struct_ptr->put = 0; + +/****************************************************************************** + * + * Function: H5C2_jb__get_last_transaction_on_disk + * + * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> + * Wednesday, February 6, 2008 + * + * Purpose: Lookup the number of the last transaction to have been + * fully written to disk, and place its transaction + * number in *trans_num_ptr. If no transaction has made + * it to disk, load zero into *trans_num_ptr. + * + * Returns: SUCCEED on success. + * + ******************************************************************************/ - /* Drag trans_tracking value into next buffer */ - (*struct_ptr->trans_tracking)[0] - = (*struct_ptr->trans_tracking)[struct_ptr->num_bufs - 1]; +herr_t +H5C2_jb__get_last_transaction_on_disk(H5C2_jbrb_t * struct_ptr, + uint64_t * trans_num_ptr) +{ + herr_t ret_value = SUCCEED; - /* reset head pointer and free space values */ - struct_ptr->head = (*struct_ptr->buf)[0]; - struct_ptr->rb_space_to_rollover = - struct_ptr->buf_size * struct_ptr->num_bufs; + FUNC_ENTER_NOAPI(H5C2_jb__get_last_transaction_on_disk, FAIL) + + /* Check Arguments */ + HDassert( trans_num_ptr != NULL ); - } /* end else */ + /* This should really be an assert, but the func enter/exit + * macros get testy if there isn't at least one goto error + * macro call in the funtion. + */ + if ( ( struct_ptr == NULL ) || + ( struct_ptr->magic != H5C2__H5C2_JBRB_T_MAGIC ) ) { - if ( H5C2_jb__flush_full_buffers(struct_ptr) < 0 ) { + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "bad struct_ptr.") + } - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_jb__flush_full_buffers() failed.\n") - } /* end if */ + /* JRM: In machine readable version, lets check to see if a sync is + * necessary, and call it only if it is. + */ + /* perform a sync to ensure everything gets to disk before continuing */ + /* Note: there is no HDfsync function, so for now, the standard + fsync is being used. */ + if ( fsync(struct_ptr->journal_file_fd) < 0 ) { - struct_ptr->cur_buf_free_space = struct_ptr->buf_size; + HGOTO_ERROR(H5E_IO, H5E_SYNCFAIL, FAIL, "Jounal file sync failed.") - } /* end if */ + } /* end if */ - } /* end else */ - - HDassert(struct_ptr->bufs_in_use <= struct_ptr->num_bufs); + * trans_num_ptr = struct_ptr->last_trans_on_disk; done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5C2_jb__write_to_buffer */ +} /* end H5C2_jb__get_last_transaction_on_disk */ /****************************************************************************** @@ -3224,10 +2966,19 @@ done: * * Returns: SUCCEED on success. * + * Changes: JRM -- 2/10/09 + * Added the journal_magic parameter and related code. + * + * Also deleted code to write the header message. + * Since the base address of the journal magic in + * the HDF5 file isn't available at this time, wait + * until our first real entry to write the header. + * ******************************************************************************/ herr_t H5C2_jb__init(H5C2_jbrb_t * struct_ptr, + const int32_t journal_magic, const char * HDF5_file_name, const char * journal_file_name, size_t buf_size, @@ -3243,16 +2994,60 @@ H5C2_jb__init(H5C2_jbrb_t * struct_ptr, FUNC_ENTER_NOAPI(H5C2_jb__init, FAIL) /* Check Arguments */ - HDassert(struct_ptr); - HDassert(HDF5_file_name); - HDassert(journal_file_name); - HDassert(buf_size > 0); - HDassert(num_bufs > 0); - HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); + HDassert( struct_ptr ); + HDassert( HDF5_file_name ); + HDassert( journal_file_name ); + HDassert( buf_size > 0 ); + HDassert( num_bufs > 0 ); + HDassert( struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC ); + + /* Initialize Fields of H5C2_jbrb_t structure. Note that we will + * overwrite some of these initializations almost immediately. + */ + struct_ptr->journal_magic = journal_magic; + struct_ptr->journal_file_fd = -1; + struct_ptr->num_bufs = num_bufs; + struct_ptr->buf_size = buf_size; + struct_ptr->bufs_in_use = 0; + struct_ptr->jvers = H5C2__JOURNAL_VERSION; + struct_ptr->get = 0; + struct_ptr->put = 0; + struct_ptr->jentry_written = FALSE; + struct_ptr->use_aio = use_aio; + struct_ptr->human_readable = human_readable; + struct_ptr->journal_is_empty = TRUE; + struct_ptr->cur_trans = 0; + struct_ptr->last_trans_on_disk = 0; + struct_ptr->trans_in_prog = FALSE; + struct_ptr->jname = HDstrdup(journal_file_name); + + if ( struct_ptr->jname == NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "allocation of space for copy of journal_file_name failed."); + } + + struct_ptr->hdf5_file_name = HDstrdup(HDF5_file_name); + + if ( struct_ptr->jname == NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "allocation of space for copy of HDF5_file_name failed."); + } + + struct_ptr->header_present = FALSE; + struct_ptr->cur_buf_free_space = buf_size; + struct_ptr->rb_space_to_rollover = num_bufs * buf_size; + struct_ptr->rb_free_space = num_bufs * buf_size; + struct_ptr->head = NULL; + struct_ptr->trans_tracking = NULL; + struct_ptr->buf = NULL; + /* Open journal file */ struct_ptr->journal_file_fd = HDopen(journal_file_name, O_WRONLY|O_CREAT|O_EXCL, 0777); + if ( struct_ptr->journal_file_fd == -1) { HDfprintf(stdout, @@ -3262,28 +3057,6 @@ H5C2_jb__init(H5C2_jbrb_t * struct_ptr, "Can't create journal file. Does it already exist?") } /* end if */ - /* Initialize Fields of H5C2_jbrb_t structure */ - /* this should be modified to check error returns, etc. Also, should - * probably do the same with the HDF5 file name. - */ - struct_ptr->jname = HDstrdup(journal_file_name); - struct_ptr->hdf5_file_name = HDF5_file_name; - struct_ptr->buf_size = buf_size; - struct_ptr->num_bufs = num_bufs; - struct_ptr->use_aio = use_aio; - struct_ptr->human_readable = human_readable; - struct_ptr->bufs_in_use = 0; - struct_ptr->trans_in_prog = FALSE; - struct_ptr->get = 0; - struct_ptr->put = 0; - struct_ptr->jvers = H5C2__JOURNAL_VERSION; - struct_ptr->cur_trans = 0; - struct_ptr->last_trans_on_disk = 0; - struct_ptr->cur_buf_free_space = struct_ptr->buf_size; - struct_ptr->rb_free_space = struct_ptr->num_bufs * struct_ptr->buf_size; - struct_ptr->rb_space_to_rollover = struct_ptr->num_bufs * struct_ptr->buf_size; - struct_ptr->jentry_written = FALSE; - struct_ptr->journal_is_empty = TRUE; /* Allocate space for the ring buffer's journal buffer pointers */ struct_ptr->buf = H5MM_malloc(struct_ptr->num_bufs * sizeof(char *)); @@ -3334,7 +3107,7 @@ H5C2_jb__init(H5C2_jbrb_t * struct_ptr, /* Make journal buffer pointers point to the right location in * chunk of allocated memory above */ - for (i=1; i<struct_ptr->num_bufs; i++) + for ( i = 1; i < struct_ptr->num_bufs; i++ ) { (*struct_ptr->buf)[i] = &((*struct_ptr->buf)[0])[i * struct_ptr->buf_size]; @@ -3342,141 +3115,18 @@ H5C2_jb__init(H5C2_jbrb_t * struct_ptr, /* Define head pointer to point at where we are writing to in the buffer */ struct_ptr->head = (*struct_ptr->buf)[struct_ptr->put]; - - /* Get the current date */ - current_date = time(NULL); - - /* Format the header message into a temporary buffer */ - HDsnprintf(temp, - (size_t)150, - "0 ver_num %ld target_file_name %s creation_date %10.10s human_readable %d\n", - struct_ptr->jvers, - struct_ptr->hdf5_file_name, - ctime(¤t_date), - struct_ptr->human_readable); - - /* Write the header message into the ring buffer */ - if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(temp), temp, FALSE, - (uint64_t)0) < 0) { - - HDfprintf(stdout, - "%s: H5C2_jb__write_to_buffer() failed.\n", - FUNC); - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_jb__write_to_buffer() failed.\n") - } /* end if */ - - /* Update boolean flags */ - struct_ptr->header_present = TRUE; - struct_ptr->journal_is_empty = FALSE; - -done: - - FUNC_LEAVE_NOAPI(ret_value) - -} /* end H5C2_jb__init */ - - -/****************************************************************************** - * - * Function: H5C2_jb__start_transaction - * - * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> - * Wednesday, February 6, 2008 - * - * Purpose: Verify that there is no transaction in progress, and - * that the supplied transaction number greater than - * the last. Then construct a start transaction message, - * and write it to the current journal buffer. Make note - * of the fact that the supplied transaction is in - * progress. - * - * Returns: SUCCEED on success. - * - ******************************************************************************/ - -herr_t -H5C2_jb__start_transaction(H5C2_jbrb_t * struct_ptr, - uint64_t trans_num) - -{ - char temp[150]; - herr_t ret_value = SUCCEED; - time_t current_date; - - FUNC_ENTER_NOAPI(H5C2_jb__start_transaction, FAIL) #if 0 /* JRM */ - HDfprintf(stdout, "%s trans_num = %lld.\n", FUNC, trans_num); -#endif /* JRM */ - /* Check Arguments */ - HDassert(struct_ptr); - HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); - - /* Verify that there is no transaction in progress */ - if ( struct_ptr->trans_in_prog != FALSE ) { - - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "Transaction already in progress.") - } /* end if */ - - /* JRM: Heads up: we may relax this constraint to rquire that the - * new transaction number is greater than the old, but possibly - * not the next integer in sequence. Will this cause problems - * with testing? - */ - - /* Verify that the supplied transaction number greater than the last */ - if ( (struct_ptr->cur_trans) >= trans_num ) { - - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "New transaction out of sequence.") - } /* end if */ - - /* Verify that header message is present in journal file or ring buffer. - * If not, write it. - */ - if ( struct_ptr->header_present == FALSE ) { - - /* Get the current date */ - current_date = time(NULL); - - HDsnprintf(temp, - (size_t)150, - "0 ver_num %ld target_file_name %s creation_date %10.10s human_readable %d\n", - struct_ptr->jvers, - struct_ptr->hdf5_file_name, - ctime(¤t_date), - struct_ptr->human_readable); - - if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(temp), temp, - FALSE, trans_num) < 0 ) { - - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_jb__write_to_buffer() failed.\n") - } /* end if */ - - struct_ptr->header_present = 1; - struct_ptr->journal_is_empty = 0; - } /* end if */ - - /* Write start transaction message */ - HDsnprintf(temp, (size_t)150, "1 bgn_trans %llu\n", trans_num); - if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(temp), temp, - FALSE, trans_num) < 0 ) { + if ( H5C2_jb__write_header_entry(struct_ptr) != SUCCEED ) { HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_jb__write_to_buffer() failed.\n") - } /* end if */ - - /* Make note of the fact that supplied transaction is in progress */ - struct_ptr->trans_in_prog = TRUE; - struct_ptr->cur_trans = trans_num; - + "H5C2_jb__write_header_entry() failed.\n") + } +#endif /* JRM */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5C2_jb__start_transaction */ +} /* end H5C2_jb__init */ /****************************************************************************** @@ -3615,31 +3265,34 @@ done: } /* end H5C2_jb__journal_entry */ -/***************************************************************************** +/****************************************************************************** * - * Function: H5C2_jb__end_transaction + * Function: H5C2_jb__start_transaction * * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> * Wednesday, February 6, 2008 * - * Purpose: Verify that the supplied transaction is in progress, - * and that at least one journal entry has been written - * under it. Then construct an end transaction message, + * Purpose: Verify that there is no transaction in progress, and + * that the supplied transaction number greater than + * the last. Then construct a start transaction message, * and write it to the current journal buffer. Make note - * that the supplied transaction is closed, and that no - * transaction is in progress. + * of the fact that the supplied transaction is in + * progress. * * Returns: SUCCEED on success. * - *****************************************************************************/ -herr_t -H5C2_jb__end_transaction(H5C2_jbrb_t * struct_ptr, - uint64_t trans_num) + ******************************************************************************/ + +herr_t +H5C2_jb__start_transaction(H5C2_jbrb_t * struct_ptr, + uint64_t trans_num) + { - char temp[25]; + char temp[150]; herr_t ret_value = SUCCEED; + time_t current_date; - FUNC_ENTER_NOAPI(H5C2_jb__end_transaction, FAIL) + FUNC_ENTER_NOAPI(H5C2_jb__start_transaction, FAIL) #if 0 /* JRM */ HDfprintf(stdout, "%s trans_num = %lld.\n", FUNC, trans_num); #endif /* JRM */ @@ -3647,286 +3300,229 @@ H5C2_jb__end_transaction(H5C2_jbrb_t * struct_ptr, HDassert(struct_ptr); HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); - /* Verify that the supplied transaction is in progress */ - if ( ( struct_ptr->trans_in_prog != TRUE ) || - ( struct_ptr->cur_trans != trans_num ) ) { + /* Verify that there is no transaction in progress */ + if ( struct_ptr->trans_in_prog != FALSE ) { HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "Transaction not in progress or bad transaction number.") + "Transaction already in progress.") } /* end if */ - - /* Verify that at least one journal entry has been written under - * the current transaction + + /* JRM: Heads up: we may relax this constraint to rquire that the + * new transaction number is greater than the old, but possibly + * not the next integer in sequence. Will this cause problems + * with testing? */ - if ( struct_ptr->jentry_written != TRUE ) { + + /* Verify that the supplied transaction number greater than the last */ + if ( (struct_ptr->cur_trans) >= trans_num ) { HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "Empty transaction -- at least one journal entry required.") + "New transaction out of sequence.") } /* end if */ + /* Verify that header message is present in journal file or ring buffer. + * If not, write it. + */ + if ( struct_ptr->header_present == FALSE ) { - /* Prepare end transaction message */ - HDsnprintf(temp, (size_t)25, "3 end_trans %llu\n", trans_num); + if ( H5C2_jb__write_header_entry(struct_ptr) != SUCCEED ) { - /* Write end transaction message */ + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__write_header_entry() failed.\n") + } + + } /* end if */ + + /* Write start transaction message */ + HDsnprintf(temp, (size_t)150, "1 bgn_trans %llu\n", trans_num); if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(temp), temp, - TRUE, trans_num ) < 0 ) { + FALSE, trans_num) < 0 ) { HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ "H5C2_jb__write_to_buffer() failed.\n") } /* end if */ - - /* reset boolean flag indicating if at least one journal entry has - * been written under transaction - */ - struct_ptr->jentry_written = FALSE; - - /* Close current transaction */ - struct_ptr->trans_in_prog = FALSE; + + /* Make note of the fact that supplied transaction is in progress */ + struct_ptr->trans_in_prog = TRUE; + struct_ptr->cur_trans = trans_num; done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5C2_jb__end_transaction */ +} /* end H5C2_jb__start_transaction */ /****************************************************************************** * - * Function: H5C2_jb__comment + * Function: H5C2_jb__takedown * * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> - * Wednesday, February 6, 2008 + * Thursday, February 7, 2008 * - * Purpose: Insert the supplied comment in the journal file. This - * call may be ignored if the journal file is machine - * readable. + * Purpose: Verify that the journal buffers are empty, and that the + * journal file has been truncated. Then close and delete + * the journal file associated with *struct_ptr, and free + * all dynamically allocated memory associated with + * *struct_ptr. * * Returns: SUCCEED on success. * ******************************************************************************/ herr_t -H5C2_jb__comment(H5C2_jbrb_t * struct_ptr, - const char * comment_ptr) +H5C2_jb__takedown(H5C2_jbrb_t * struct_ptr) + { - char * temp = NULL; - size_t temp_len; herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI(H5C2_jb__comment, FAIL) + hbool_t verbose = FALSE; + FUNC_ENTER_NOAPI(H5C2_jb__takedown, FAIL) + + if ( verbose ) { + + HDfprintf(stdout, "%s: entering.\n", FUNC); + } + /* Check Arguments */ HDassert(struct_ptr); - HDassert(comment_ptr); HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); - HDassert(struct_ptr->hdf5_file_name); - - /* Verify that header message is present in journal file or ring buffer. - * If not, write it. - */ - if ( struct_ptr->header_present == FALSE ) { - - char buf[150]; - time_t current_date; + + /* Verify that the journal buffers are empty */ + if ( struct_ptr->bufs_in_use != 0 ) { - /* Get the current date */ - current_date = time(NULL); + if ( verbose ) { + HDfprintf(stdout, "%s: Attempt to takedown with non-empty buffers.\n", + FUNC); + } + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Attempt to takedown with non-empty buffers.") + } /* end if */ - HDsnprintf(buf, - (size_t)150, - "0 ver_num %ld target_file_name %s creation_date %10.10s human_readable %d\n", - struct_ptr->jvers, - struct_ptr->hdf5_file_name, - ctime(¤t_date), - struct_ptr->human_readable); + /* Verify that the journal file has been truncated */ + if (struct_ptr->journal_is_empty != TRUE) { - if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(buf), buf, - FALSE, struct_ptr->cur_trans) < 0 ) { + if ( verbose ) { + HDfprintf(stdout, + "%s: Attempt to takedown with journal file not truncated.\n", + FUNC); + } + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Attempt to takedown with journal file not truncated.") + } /* end if */ - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_jb__write_to_buffer() failed.\n") - } /* end if */ + /* Close and delete the journal file associated with struct_ptr */ + if ( HDclose(struct_ptr->journal_file_fd) < 0 ) { - struct_ptr->header_present = 1; - struct_ptr->journal_is_empty = 0; + if ( verbose ) { + HDfprintf(stdout, + "%s: journal file close failed. errno = %d(%s), fd = %d.\n", + FUNC, errno, strerror(errno), struct_ptr->journal_file_fd); + } + HGOTO_ERROR(H5E_IO, H5E_CLOSEERROR, FAIL, "Jounal file close failed.") } /* end if */ - temp_len = HDstrlen(comment_ptr) + 11; - if ( ( temp = H5MM_malloc(HDstrlen(comment_ptr) + 11) ) == NULL ) { + if ( HDremove(struct_ptr->jname) < 0) { - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ - "allocation of temp buffer failed."); + if ( verbose ) { + HDfprintf(stdout, + "%s: journal file remove failed. errno = %d(%s).\n", + FUNC, errno, strerror(errno)); + } + HGOTO_ERROR(H5E_IO, H5E_REMOVEFAIL, FAIL, "Jounal file close failed.") } /* end if */ - /* Write comment message */ - HDsnprintf(temp, temp_len, "C comment %s", comment_ptr); - - if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(temp), temp, FALSE, struct_ptr->cur_trans ) < 0 ) { + /* Free all memory associated with struct_ptr */ - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_jb__write_to_buffer() failed.\n") - } /* end if */ + if ( struct_ptr->jname != NULL ) { - if ( H5C2_jb__write_to_buffer(struct_ptr, 1, "\n", FALSE, struct_ptr->cur_trans ) < 0 ) { + struct_ptr->jname = H5MM_xfree(struct_ptr->jname); - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_jb__write_to_buffer() failed.\n") - } /* end if */ + if ( struct_ptr->jname != NULL ) { -done: + if ( verbose ) { - if ( temp != NULL ) { + HDfprintf(stdout, "%s: free of jname failed.\n", FUNC); - temp = H5MM_xfree(temp); - if ( temp != NULL ) { + } HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ - "free of assembly buffer failed."); + "free of jname failed."); } } - FUNC_LEAVE_NOAPI(ret_value) + if ( struct_ptr->hdf5_file_name != NULL ) { -} /* end H5C2_jb__comment */ + struct_ptr->hdf5_file_name = H5MM_xfree(struct_ptr->hdf5_file_name); - -/****************************************************************************** - * - * Function: H5C2_jb__eoa - * - * Programmer: Mike McGreevy <mamcgree@hdfgroup.org> - * July 29, 2008 - * - * Purpose: Insert the supplied EOA into the journal file. - * - * Returns: SUCCEED on success. - * - ******************************************************************************/ + if ( struct_ptr->hdf5_file_name != NULL ) { -herr_t -H5C2_jb__eoa(H5C2_jbrb_t * struct_ptr, - haddr_t eoa) -{ - char temp[40]; - size_t temp_len = 40; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI(H5C2_jb__eoa, FAIL) - - /* Check Arguments */ - HDassert(struct_ptr); - HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); - HDassert(struct_ptr->hdf5_file_name); - - /* Verify that header message is present in journal file or ring buffer. - * If not, write it. - */ - if ( struct_ptr->header_present == FALSE ) { - - char buf[150]; - time_t current_date; - - /* Get the current date */ - current_date = time(NULL); - - HDsnprintf(buf, - (size_t)150, - "0 ver_num %ld target_file_name %s creation_date %10.10s human_readable %d\n", - struct_ptr->jvers, - struct_ptr->hdf5_file_name, - ctime(¤t_date), - struct_ptr->human_readable); - - if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(buf), buf, - FALSE, struct_ptr->cur_trans) < 0 ) { - - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_jb__write_to_buffer() failed.\n") - } /* end if */ + if ( verbose ) { - struct_ptr->header_present = 1; - struct_ptr->journal_is_empty = 0; - } /* end if */ + HDfprintf(stdout, "%s: free of hdf5_file_name failed.\n", FUNC); - /* Write EOA message */ - HDsnprintf(temp, temp_len, "E eoa_value 0x%llx", eoa); + } - if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(temp), temp, FALSE, struct_ptr->cur_trans ) < 0 ) { + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "free of hdf5_file_name failed."); + } + } - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_jb__write_to_buffer() failed.\n") - } /* end if */ + if ( (*struct_ptr->buf)[0] != NULL ) { - if ( H5C2_jb__write_to_buffer(struct_ptr, 1, "\n", FALSE, struct_ptr->cur_trans ) < 0 ) { + (*struct_ptr->buf)[0] = H5MM_xfree((*struct_ptr->buf)[0]); + if ( (*struct_ptr->buf)[0] != NULL ) { - HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ - "H5C2_jb__write_to_buffer() failed.\n") - } /* end if */ + if ( verbose ) { + HDfprintf(stdout, "%s: free of buffers failed.\n", FUNC); + } + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "free of buffers failed."); + } + } -done: + if ( struct_ptr->buf != NULL ) { - FUNC_LEAVE_NOAPI(ret_value) + struct_ptr->buf = H5MM_xfree(struct_ptr->buf); + if ( struct_ptr->buf != NULL ) { -} /* end H5C2_jb__eoa */ + if ( verbose ) { + HDfprintf(stdout, "%s: free of buffer ptr array faileid.\n", + FUNC); + } + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "free of buffer pointer array failed."); + } + } - -/****************************************************************************** - * - * Function: H5C2_jb__get_last_transaction_on_disk - * - * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> - * Wednesday, February 6, 2008 - * - * Purpose: Lookup the number of the last transaction to have been - * fully written to disk, and place its transaction - * number in *trans_num_ptr. If no transaction has made - * it to disk, load zero into *trans_num_ptr. - * - * Returns: SUCCEED on success. - * - ******************************************************************************/ + if ( struct_ptr->trans_tracking != NULL ) { -herr_t -H5C2_jb__get_last_transaction_on_disk(H5C2_jbrb_t * struct_ptr, - uint64_t * trans_num_ptr) -{ - herr_t ret_value = SUCCEED; + struct_ptr->trans_tracking = H5MM_xfree(struct_ptr->trans_tracking); - FUNC_ENTER_NOAPI(H5C2_jb__get_last_transaction_on_disk, FAIL) - - /* Check Arguments */ - HDassert( trans_num_ptr != NULL ); + if ( struct_ptr->trans_tracking != NULL ) { - /* This should really be an assert, but the func enter/exit - * macros get testy if there isn't at least one goto error - * macro call in the funtion. - */ - if ( ( struct_ptr == NULL ) || - ( struct_ptr->magic != H5C2__H5C2_JBRB_T_MAGIC ) ) { + if ( verbose ) { + HDfprintf(stdout, + "%s: free of trans tracking array faileid.\n", + FUNC); + } - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "bad struct_ptr.") + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "free of transaction tracking array failed."); + } } - /* JRM: In machine readable version, lets check to see if a sync is - * necessary, and call it only if it is. - */ - /* perform a sync to ensure everything gets to disk before continuing */ - /* Note: there is no HDfsync function, so for now, the standard - fsync is being used. */ - if ( fsync(struct_ptr->journal_file_fd) < 0 ) { - - HGOTO_ERROR(H5E_IO, H5E_SYNCFAIL, FAIL, "Jounal file sync failed.") - - } /* end if */ +done: - * trans_num_ptr = struct_ptr->last_trans_on_disk; + if ( verbose ) { -done: + HDfprintf(stdout, "%s: exiting.\n", FUNC); + fflush(stdout); + } FUNC_LEAVE_NOAPI(ret_value) -} /* end H5C2_jb__get_last_transaction_on_disk */ +} /* end H5C2_jb__takedown */ /****************************************************************************** @@ -4006,193 +3602,456 @@ done: /****************************************************************************** * - * Function: H5C2_jb__takedown + * Function: H5C2_jb__write_header_entry * - * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> - * Thursday, February 7, 2008 + * Programmer: John Mainzer + * 2/12/09 * - * Purpose: Verify that the journal buffers are empty, and that the - * journal file has been truncated. Then close and delete - * the journal file associated with *struct_ptr, and free - * all dynamically allocated memory associated with - * *struct_ptr. + * Purpose: Write the header message to the journal file. + * + * This message appear exactly once in every journal + * file, and is always the first message in the file. + * It identifies the journal file, and contains + * information required to run the journal, should + * that be necessary. * + * It is always in human readable format. + * * Returns: SUCCEED on success. + * FAIL on failure. + * + * Changes: JRM -- 3/21/09 + * Moved the entry tag strings into #defines. + * Replaced all white space in the creation date + * string with underscores. * ******************************************************************************/ herr_t -H5C2_jb__takedown(H5C2_jbrb_t * struct_ptr) +H5C2_jb__write_header_entry(H5C2_jbrb_t * struct_ptr) { - herr_t ret_value = SUCCEED; - hbool_t verbose = FALSE; + herr_t ret_value = SUCCEED; + hbool_t verbose = FALSE; + char *buf; + char * p; + char time_buf[32]; + int chars_written; + int i; + size_t file_name_len; + size_t buf_len; + time_t current_date; - FUNC_ENTER_NOAPI(H5C2_jb__takedown, FAIL) + FUNC_ENTER_NOAPI(H5C2_jb__write_header_entry, FAIL) - if ( verbose ) { + /* Check Arguments */ + HDassert( struct_ptr ); + HDassert( struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC ); + HDassert( struct_ptr->hdf5_file_name != NULL ); + HDassert( struct_ptr->header_present == FALSE ); + HDassert( struct_ptr->journal_is_empty == TRUE ); - HDfprintf(stdout, "%s: entering.\n", FUNC); - } + file_name_len = strlen(struct_ptr->hdf5_file_name); - /* Check Arguments */ - HDassert(struct_ptr); - HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); + HDassert( file_name_len > 0 ); + + buf_len = file_name_len + 256; - /* Verify that the journal buffers are empty */ - if ( struct_ptr->bufs_in_use != 0 ) { + /* Allocate space for journal buffers */ + buf = H5MM_malloc(buf_len); - if ( verbose ) { - HDfprintf(stdout, "%s: Attempt to takedown with non-empty buffers.\n", - FUNC); - } - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "Attempt to takedown with non-empty buffers.") - } /* end if */ + if ( buf == NULL ) { - /* Verify that the journal file has been truncated */ - if (struct_ptr->journal_is_empty != TRUE) { + if ( verbose ) { - if ( verbose ) { - HDfprintf(stdout, - "%s: Attempt to takedown with journal file not truncated.\n", - FUNC); - } - HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ - "Attempt to takedown with journal file not truncated.") + HDfprintf(stdout, "%s: buffer allocation failed.\n", FUNC); + } + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "buffer allocation failed."); } /* end if */ + + /* Get the current date */ + current_date = time(NULL); - /* Close and delete the journal file associated with struct_ptr */ - if ( HDclose(struct_ptr->journal_file_fd) < 0 ) { + /* load ascii representation of current_date into time_buf[], + * replacing white space with underscores. + */ + time_buf[31] = '\0'; /* just to be safe */ - if ( verbose ) { - HDfprintf(stdout, - "%s: journal file close failed. errno = %d(%s), fd = %d.\n", - FUNC, errno, strerror(errno), struct_ptr->journal_file_fd); - } - HGOTO_ERROR(H5E_IO, H5E_CLOSEERROR, FAIL, "Jounal file close failed.") - } /* end if */ + if ( (p = HDctime(¤t_date)) == NULL ) { - if ( HDremove(struct_ptr->jname) < 0) { + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "Can't get ascii representation of current date.") - if ( verbose ) { - HDfprintf(stdout, - "%s: journal file remove failed. errno = %d(%s).\n", - FUNC, errno, strerror(errno)); - } - HGOTO_ERROR(H5E_IO, H5E_REMOVEFAIL, FAIL, "Jounal file close failed.") - } /* end if */ + } else { - /* Free all memory associated with struct_ptr */ + /* copy the string into time_buf, replacing white space with + * underscores. + * + * Do this to make parsing the header easier. + */ + i = 0; - if ( struct_ptr->jname != NULL ) { + while ( ( i < 31 ) && ( *p != '\0' ) ) { - struct_ptr->jname = H5MM_xfree(struct_ptr->jname); - if ( struct_ptr->jname != NULL ) { + if ( isspace(*p) ) { - if ( verbose ) { - HDfprintf(stdout, "%s: free of jname failed.\n", FUNC); - } - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ - "free of jname failed."); - } - } + time_buf[i] = '_'; - if ( (*struct_ptr->buf)[0] != NULL ) { + } else { - (*struct_ptr->buf)[0] = H5MM_xfree((*struct_ptr->buf)[0]); - if ( (*struct_ptr->buf)[0] != NULL ) { + time_buf[i] = *p; + } - if ( verbose ) { - HDfprintf(stdout, "%s: free of buffers failed.\n", FUNC); - } - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ - "free of buffers failed."); + i++; + p++; } + + time_buf[i] = '\0'; } - if ( struct_ptr->buf != NULL ) { + /* Format the header message in the temporary buffer */ - struct_ptr->buf = H5MM_xfree(struct_ptr->buf); - if ( struct_ptr->buf != NULL ) { + chars_written = + HDsnprintf(buf, + buf_len - 1, + "0 %s %ld %s %s %s %d %s %10.10s %s %d\n", + H5C2_JNL__VER_NUM_TAG, + struct_ptr->jvers, + H5C2_JNL__TGT_FILE_NAME_TAG, + struct_ptr->hdf5_file_name, + H5C2_JNL__JNL_MAGIC_TAG, + (int)(struct_ptr->journal_magic), + H5C2_JNL__CREATION_DATE_TAG, + time_buf, + H5C2_JNL__HUMAN_READABLE_TAG, + struct_ptr->human_readable); - if ( verbose ) { - HDfprintf(stdout, "%s: free of buffer ptr array faileid.\n", - FUNC); - } - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ - "free of buffer pointer array failed."); + if ( chars_written >= buf_len - 1 ) { + + if ( verbose ) { + + HDfprintf(stdout, "%s: tried to overwrite buffer.\n", FUNC); } + + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCOPY, FAIL, \ + "tried to overwrite buffer."); } - if ( struct_ptr->trans_tracking != NULL ) { + HDassert( strlen(buf) < buf_len ); - struct_ptr->trans_tracking = H5MM_xfree(struct_ptr->trans_tracking); - if ( struct_ptr->trans_tracking != NULL ) { + /* Write the header message into the ring buffer */ + if ( H5C2_jb__write_to_buffer(struct_ptr, HDstrlen(buf), buf, FALSE, + (uint64_t)0) < 0) { - if ( verbose ) { - HDfprintf(stdout, "%s: free of trans tracking array faileid.\n", - FUNC); - } - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ - "free of transaction tracking array failed."); + if ( verbose ) { + + HDfprintf(stdout, + "%s: H5C2_jb__write_to_buffer() failed.\n", + FUNC); } - } + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__write_to_buffer() failed.\n") + } /* end if */ + + /* Update boolean flags */ + struct_ptr->header_present = TRUE; + struct_ptr->journal_is_empty = FALSE; done: - if ( verbose ) { + if ( buf != NULL ) { - HDfprintf(stdout, "%s: exiting.\n", FUNC); - fflush(stdout); + buf = H5MM_xfree(buf); + + if ( buf != NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "free of buf failed."); + } } + FUNC_LEAVE_NOAPI(ret_value) -} /* end H5C2_jb__takedown */ +} /* end H5C2_jb__write_header_entry() */ /****************************************************************************** * - * Function: H5C2_jb__bin2hex + * Function: H5C2_jb__write_to_buffer * * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> - * Tuesday, March 4, 2008 + * Wednesday, February 6, 2008 * - * Purpose: Convert binary data into hexadecimal. + * Purpose: Put the contents of data into the journal buffers. This + * is done as follows: While the data to be written is + * larger than the amount of space left in the ring buffer, + * the ring buffer is filled to capacity with data and + * flushed. This repeats until the unwritten data remaining + * can fit in the ring buffer without having to loop around + * to the top. + * + * At this point, the rest of the data can just be written + * without having to break it up further. In the event + * the data covers more than one journal buffer, the get + * and put indices are updated to state this fact. Any + * journal buffers that were filled during the write are + * flushed. * * Returns: SUCCEED on success. * ******************************************************************************/ herr_t -H5C2_jb__bin2hex(const uint8_t * buf, - char * hexdata, - size_t * hexlength, - size_t buf_size) - +H5C2_jb__write_to_buffer(H5C2_jbrb_t * struct_ptr, + size_t size, + const char * data, + hbool_t is_end_trans, + uint64_t trans_num) { - size_t v; /* Local index variable */ - uint8_t c; - char * t; + herr_t ret_value = SUCCEED; + unsigned long track_last_trans = 0; + int oldput = 0; + int i; - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5C2_jb__bin2hex) + FUNC_ENTER_NOAPI(H5C2_jb__write_to_buffer, FAIL) - t = hexdata; - t[0] = ' '; - for (v = 0; v < buf_size; v++) { + /* Check Arguments */ + HDassert(struct_ptr); + HDassert(data); + HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); + HDassert(HDstrlen(data) == size); + HDassert(struct_ptr->rb_space_to_rollover <= + struct_ptr->num_bufs * struct_ptr->buf_size); + HDassert(struct_ptr->rb_space_to_rollover > 0); - t = &hexdata[v * 3 + 1]; - c = buf[v]; - HDsnprintf(t, (size_t)3, "%02x ", c); - t[2] = ' '; + /* If the data size exceeds the bounds of the ring buffer's allocated + * memory, loop around to top + */ + if (size >= struct_ptr->rb_space_to_rollover) { - } /* end for */ - t[3] = '\n'; - t[4] = 0; + while (size >= struct_ptr->rb_space_to_rollover) { + + /* Assertions */ + HDassert(size != 0); + HDassert(HDstrlen(data) >= struct_ptr->rb_space_to_rollover); - * hexlength = v * 3 + 2; + /* fill up remaining space in the ring buffer */ + HDmemcpy(struct_ptr->head, data, struct_ptr->rb_space_to_rollover); + + /* move head to point to start of ring buffer */ + struct_ptr->head = (*struct_ptr->buf)[0]; - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5C2_jb__bin2hex*/ + /* make note of last transaction on disk */ + track_last_trans = (*struct_ptr->trans_tracking)[struct_ptr->put]; + + /* update rb_free_space */ + struct_ptr->rb_free_space -= struct_ptr->rb_space_to_rollover; + + /* Fill out the remainder of the trans_tracking array with + the most recent transaction in the array.*/ + (*struct_ptr->trans_tracking)[0] = track_last_trans; + for (i=struct_ptr->put; i<struct_ptr->num_bufs; i++) + { + (*struct_ptr->trans_tracking)[i] = track_last_trans; + } + + /* reset put index */ + struct_ptr->put = 0; + + /* update bufs_in_use as necessary */ + struct_ptr->bufs_in_use = struct_ptr->num_bufs - struct_ptr->get; + + /* check to see if trans_tracking needs to be updated. If so, + then update it */ + if ((size == struct_ptr->rb_space_to_rollover) && + (is_end_trans == TRUE)) { + + (*struct_ptr->trans_tracking)[struct_ptr->num_bufs - 1] + = trans_num; + (*struct_ptr->trans_tracking)[0] = trans_num; + } + + /* flush buffers */ + if ( H5C2_jb__flush_full_buffers(struct_ptr) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__flush_full_buffers() failed.\n") + } + + /* update remaining size of data to be written */ + size = size - struct_ptr->rb_space_to_rollover; + + /* update the data pointer to point to the remaining data to be + * written + */ + data = &data[struct_ptr->rb_space_to_rollover]; + + /* update the amount of space left at end of ring buffer */ + struct_ptr->rb_space_to_rollover = + struct_ptr->buf_size * struct_ptr->num_bufs; + + /* update the amount of space in the current buffer */ + struct_ptr->cur_buf_free_space = struct_ptr->buf_size; + + } /* end while */ + } /* end if */ + + /* If the size of the data exceeds the bounds of a single journal + * buffer, will write into multiple + */ + if (size > struct_ptr->cur_buf_free_space) { + + HDassert(struct_ptr->cur_buf_free_space != 0); + + /* write data into journal buffers */ + HDmemcpy(struct_ptr->head, data, size); + + /* update head pointer */ + struct_ptr->head = &struct_ptr->head[size]; + + /* make note of last transaction on disk */ + track_last_trans = (*struct_ptr->trans_tracking)[struct_ptr->put]; + oldput = struct_ptr->put; + + /* update rb_free_space */ + struct_ptr->rb_free_space -= size; + + /* update put index */ + struct_ptr->put += + (size-struct_ptr->cur_buf_free_space)/(struct_ptr->buf_size) + 1; + + /* Drag the last transaction in a filled buffer value residing in the + old put location through the trans_tracking array to the new + corresponding put position. */ + for (i=oldput; i<struct_ptr->put+1; i++) + { + (*struct_ptr->trans_tracking)[i] = track_last_trans; + } + + /* update current buffer usage */ + struct_ptr->cur_buf_free_space = + struct_ptr->rb_space_to_rollover - size - + (struct_ptr->num_bufs - (struct_ptr->put + 1)) * + (struct_ptr->buf_size ); + + /* update bufs_in_use as necessary */ + struct_ptr->bufs_in_use = struct_ptr->put - struct_ptr->get; + if (struct_ptr->cur_buf_free_space < struct_ptr->buf_size) { + + struct_ptr->bufs_in_use++; + } + + /* check to see if trans_tracking needs to be updated. If so, + then update it */ + if (is_end_trans == TRUE) { + + if (struct_ptr->cur_buf_free_space == struct_ptr->buf_size) { + (*struct_ptr->trans_tracking)[struct_ptr->put - 1] = trans_num; + } + else { + (*struct_ptr->trans_tracking)[struct_ptr->put] = trans_num; + } + + } /* end if */ + + /* flush buffers */ + if ( H5C2_jb__flush_full_buffers(struct_ptr) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__flush_full_buffers() failed.\n") + } + + /* update space left at end of ring buffer */ + struct_ptr->rb_space_to_rollover -= size; + + } /* end if */ + + /* if the data can fit in the remaining space in the current journal + * buffer indexed by put + */ + else if (size > 0) { + + HDassert(size <= struct_ptr->cur_buf_free_space); + + /* write data into journal buffer */ + HDmemcpy(struct_ptr->head, data, size); + + /* increment bufs_in_use as necessary */ + if ( ( struct_ptr->bufs_in_use == 0 ) ) { + + struct_ptr->bufs_in_use++; + } + + /* update head pointer */ + struct_ptr->head = &struct_ptr->head[size]; + + /* update rb_free_space */ + struct_ptr->rb_free_space -= size; + + /* update current buffer usage */ + struct_ptr->cur_buf_free_space -= size; + + /* update end of buffer space */ + struct_ptr->rb_space_to_rollover -= size; + + /* check to see if trans_tracking needs to be updated. If so, + then update it */ + if (is_end_trans == TRUE) { + + (*struct_ptr->trans_tracking)[struct_ptr->put] + = trans_num; + } /* end if */ + + /* if buffer is full, flush it, and loop to the top of the + * ring buffer if at the end. + */ + if (struct_ptr->cur_buf_free_space == 0) { + + if ( struct_ptr->put != (struct_ptr->num_bufs - 1) ) { + struct_ptr->put += 1; + + /* Drag trans_tracking value into next buffer */ + (*struct_ptr->trans_tracking)[struct_ptr->put] + = (*struct_ptr->trans_tracking)[struct_ptr->put - 1]; + + } /* end if */ + + else { + + struct_ptr->put = 0; + + /* Drag trans_tracking value into next buffer */ + (*struct_ptr->trans_tracking)[0] + = (*struct_ptr->trans_tracking)[struct_ptr->num_bufs - 1]; + + /* reset head pointer and free space values */ + struct_ptr->head = (*struct_ptr->buf)[0]; + struct_ptr->rb_space_to_rollover = + struct_ptr->buf_size * struct_ptr->num_bufs; + + } /* end else */ + + if ( H5C2_jb__flush_full_buffers(struct_ptr) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__flush_full_buffers() failed.\n") + } /* end if */ + + struct_ptr->cur_buf_free_space = struct_ptr->buf_size; + + } /* end if */ + + } /* end else */ + + HDassert(struct_ptr->bufs_in_use <= struct_ptr->num_bufs); + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5C2_jb__write_to_buffer */ diff --git a/src/H5C2pkg.h b/src/H5C2pkg.h index 3510dc7..af3ac81 100644 --- a/src/H5C2pkg.h +++ b/src/H5C2pkg.h @@ -62,9 +62,17 @@ * * * magic: Unsigned 32-bit integer always set to - * H5C2__H5C2_JBRB_T_MAGIC. This field is used to validate - * pointers to instances of H5C_jbrb_t. - * + * H5C2__H5C2_JBRB_T_MAGIC. This field is used to + * validate pointers to instances of H5C_jbrb_t. + * + * journal_magic: int32_t used to store a randomly selected integer + * used to tag both the journal file and the + * mdj_config_block. Should the journal ever be + * run, we will check to see if the magic number + * from the target HDF5 file matches that in the + * journal, and refuse to run the journal if it does + * not. + * * journal_file_fd: File Descriptor of the journal file that is being * written to from this ring buffer. * @@ -157,9 +165,17 @@ #define H5C2__H5C2_JBRB_T_MAGIC (unsigned)0x00D0A03 #define H5C2__JOURNAL_VERSION 1 +/* tags used to mark entries in the journal file header */ +#define H5C2_JNL__VER_NUM_TAG "ver_num" +#define H5C2_JNL__TGT_FILE_NAME_TAG "target_file_name" +#define H5C2_JNL__JNL_MAGIC_TAG "journal_magic" +#define H5C2_JNL__CREATION_DATE_TAG "creation_date" +#define H5C2_JNL__HUMAN_READABLE_TAG "human_readable" + struct H5C2_jbrb_t { uint32_t magic; + int32_t journal_magic; int journal_file_fd; int num_bufs; size_t buf_size; @@ -794,45 +810,17 @@ typedef struct H5C2_mdjsc_record_t * been modified have been written to disk in the journal * file. * - * mdj_file_name_ptr: Pointer to a string containing the path of the - * journal file, or NULL if this path is undefined. - * At present, the journal will always be stored in an - * external file, so this field must be defined if - * journaling is enabled. - * - * To avoid allocating extra memory, mdj_file_name_ptr - * points into the approprite location in the in core - * image of the metadata journaling configuration block. - * - * mdj_conf_block_addr: Address of the metadata journaling configuration - * block on disk, or HADDR_UNDEF if that block is undefined. - * - * mdj_conf_block_len: Length (in bytes) of the metadata journaling - * configuration block, or 0 if that block is undefined. - * - * mdj_conf_block_ptr: Pointer to a dynamically allocated chunk of - * memory of size mdj_conf_block_len used to construct - * an image of the on disk metadata journaling configuration - * block. This block is used to record the path of the - * journal file in the HDF5 file, so that it can be - * found in the event of a crash. + * jnl_magic: Randomly selected int32_t used to reduce the possibility + * of running the wrong journal on an HDF5 file. The basic + * idea is to pick a random number, store it in both the HDF5 + * file and the journal file, and then refuse to run the + * journal unless the numbers match. * - * The metadata journaling configuration block has the - * following format: + * jnl_file_name_len: Length of the journal file name, or zero if the + * journal file name is undefined. * - * 4 bytes signature - * - * 1 byte version - * - * 4 bytes path length - * - * variable string containing path of journal file - * - * 4 bytes checksum - * - * The base address and lenth of the metadata journaling - * configuration block is stored in the mdj_msg superblock - * extension message. + * jnl_file_name: Array of char of length H5C2__MAX_JOURNAL_FILE_NAME_LEN + * + 1 used to store the journal file path. * * mdj_jbrb: Instance of H5C2_jbrb_t used to manage logging of journal * entries to the journal file. @@ -1160,16 +1148,6 @@ typedef struct H5C2_mdjsc_record_t #define H5C2__PREFIX_LEN 32 #define H5C2__MAX_API_NAME_LEN 128 -#define H5C2__JOURNAL_MAGIC_LEN (size_t)4 -#define H5C2__JOURNAL_CONF_MAGIC "MDJC" -#define H5C2__JOURNAL_CONF_VERSION ((uint8_t)1) -#define H5C2__JOURNAL_BLOCK_LEN(pathLen, f) \ - ( H5C2__JOURNAL_MAGIC_LEN + \ - 1 + /* version */ \ - H5F_SIZEOF_SIZE(f) + \ - ((pathLen) + 1) + \ - 4 /* checksum */ ) - #define H5C2__MIN_MDJSC_CB_TBL_LEN 16 #define H5C2__MDJSC_CB_TBL_MIN_ACTIVE_RATIO 0.25 @@ -1216,7 +1194,7 @@ struct H5C2_t int32_t pel_len; size_t pel_size; - H5C2_cache_entry_t * pel_head_ptr; + H5C2_cache_entry_t * pel_head_ptr; H5C2_cache_entry_t * pel_tail_ptr; int32_t LRU_list_len; @@ -1259,10 +1237,10 @@ struct H5C2_t char trans_api_name[H5C2__MAX_API_NAME_LEN]; uint64_t trans_num; uint64_t last_trans_on_disk; - char * mdj_file_name_ptr; - haddr_t mdj_conf_block_addr; - hsize_t mdj_conf_block_len; - void * mdj_conf_block_ptr; + int32_t jnl_magic; + int32_t jnl_file_name_len; + char jnl_file_name[H5C2__MAX_JOURNAL_FILE_NAME_LEN + + 1]; struct H5C2_jbrb_t mdj_jbrb; int32_t tl_len; size_t tl_size; diff --git a/src/H5C2private.h b/src/H5C2private.h index 833bfa1..c9e55ca 100644 --- a/src/H5C2private.h +++ b/src/H5C2private.h @@ -1591,17 +1591,35 @@ H5_DLL herr_t H5C2_update_for_new_last_trans_on_disk(H5C2_t * cache_ptr, typedef struct H5C2_jbrb_t H5C2_jbrb_t; +H5_DLL herr_t H5C2_jb__bin2hex(const uint8_t * buf, + char * hexdata, + size_t * hexlength, + size_t buf_size); + +H5_DLL herr_t H5C2_jb__comment(H5C2_jbrb_t * struct_ptr, + const char * comment_ptr); + +H5_DLL herr_t H5C2_jb__end_transaction(H5C2_jbrb_t * struct_ptr, + uint64_t trans_num); + +H5_DLL herr_t H5C2_jb__eoa(H5C2_jbrb_t * struct_ptr, + haddr_t eoa); + +H5_DLL herr_t H5C2_jb__get_last_transaction_on_disk(H5C2_jbrb_t * struct_ptr, + uint64_t * trans_num_ptr); + H5_DLL herr_t H5C2_jb__flush_full_buffers(H5C2_jbrb_t * struct_ptr); H5_DLL herr_t H5C2_jb__flush(H5C2_jbrb_t * struct_ptr); -H5_DLL herr_t H5C2_jb__write_to_buffer(H5C2_jbrb_t * struct_ptr, - size_t size, - const char * data, - hbool_t is_end_trans, - uint64_t trans_num); +H5_DLL herr_t H5C2_jb__journal_entry(H5C2_jbrb_t * struct_ptr, + uint64_t trans_num, + haddr_t base_addr, + size_t length, + const uint8_t * body); H5_DLL herr_t H5C2_jb__init(H5C2_jbrb_t * struct_ptr, + const int32_t journal_magic, const char * HDF5_file_name, const char * journal_file_name, size_t buf_size, @@ -1612,35 +1630,21 @@ H5_DLL herr_t H5C2_jb__init(H5C2_jbrb_t * struct_ptr, H5_DLL herr_t H5C2_jb__start_transaction(H5C2_jbrb_t * struct_ptr, uint64_t trans_num); -H5_DLL herr_t H5C2_jb__journal_entry(H5C2_jbrb_t * struct_ptr, - uint64_t trans_num, - haddr_t base_addr, - size_t length, - const uint8_t * body); - -H5_DLL herr_t H5C2_jb__end_transaction(H5C2_jbrb_t * struct_ptr, - uint64_t trans_num); - -H5_DLL herr_t H5C2_jb__comment(H5C2_jbrb_t * struct_ptr, - const char * comment_ptr); - -H5_DLL herr_t H5C2_jb__eoa(H5C2_jbrb_t * struct_ptr, - haddr_t eoa); - -H5_DLL herr_t H5C2_jb__get_last_transaction_on_disk(H5C2_jbrb_t * struct_ptr, - uint64_t * trans_num_ptr); +H5_DLL herr_t H5C2_jb__takedown(H5C2_jbrb_t * struct_ptr); H5_DLL herr_t H5C2_jb__trunc(H5C2_jbrb_t * struct_ptr); -H5_DLL herr_t H5C2_jb__takedown(H5C2_jbrb_t * struct_ptr); +H5_DLL herr_t H5C2_jb__write_header_entry(H5C2_jbrb_t * struct_ptr); + +H5_DLL herr_t H5C2_jb__write_to_buffer(H5C2_jbrb_t * struct_ptr, + size_t size, + const char * data, + hbool_t is_end_trans, + uint64_t trans_num); -H5_DLL herr_t H5C2_jb__bin2hex(const uint8_t * buf, - char * hexdata, - size_t * hexlength, - size_t buf_size); /*****************************************************************************/ -/********** journal config block management function definitions: ************/ +/***** superblock journaling message management function definitions: ********/ /*****************************************************************************/ H5_DLL herr_t H5C2_check_for_journaling(H5F_t * f, @@ -1648,25 +1652,13 @@ H5_DLL herr_t H5C2_check_for_journaling(H5F_t * f, H5C2_t * cache_ptr, hbool_t journal_recovered); -H5_DLL herr_t H5C2_create_journal_config_block(const H5F_t *f, - hid_t dxpl_id, - const char * journal_file_name_ptr); - -H5_DLL herr_t H5C2_discard_journal_config_block(const H5F_t * f, - hid_t dxpl_id); - H5_DLL herr_t H5C2_get_journaling_in_progress(const H5F_t * f, hid_t dxpl_id, H5C2_t * cache_ptr); -H5_DLL herr_t H5C2_load_journal_config_block(const H5F_t * f, - hid_t dxpl_id, - H5C2_t * cache_ptr, - haddr_t block_addr, - hsize_t block_len); - H5_DLL herr_t H5C2_mark_journaling_in_progress(H5F_t * f, hid_t dxpl_id, + const int32_t journal_magic, const char * journal_file_name_ptr); H5_DLL herr_t H5C2_unmark_journaling_in_progress(H5F_t * f, diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h index 08a53a5..1318eb8 100644 --- a/src/H5Fpkg.h +++ b/src/H5Fpkg.h @@ -138,7 +138,12 @@ typedef struct H5F_file_t { struct H5G_t *root_grp; /* Open root group */ H5FO_t *open_objs; /* Open objects in file */ H5RC_t *grp_btree_shared; /* Ref-counted group B-tree node info */ - hbool_t mdc_jrnl_enabled; /* TRUE iff journaling is in progress */ + hbool_t mdc_jnl_enabled; /* TRUE iff journaling is in progress */ + int32_t mdc_jnl_magic; /* journal file magic -- if defined */ + size_t mdc_jnl_file_name_len; /* journal file name length */ + char mdc_jnl_file_name[H5C2__MAX_JOURNAL_FILE_NAME_LEN + 1]; + /* journal file name -- if defined */ +/* todo -- delete the following lines. -- JRM */ haddr_t mdc_jrnl_block_loc; /* Rel addr of mdc journal block */ hsize_t mdc_jrnl_block_len; /* Length of mdc journal block */ } H5F_file_t; diff --git a/src/H5Fsuper.c b/src/H5Fsuper.c index 2df6ac1..2e1f564 100644 --- a/src/H5Fsuper.c +++ b/src/H5Fsuper.c @@ -356,9 +356,10 @@ H5F_super_read(H5F_t *f, hid_t dxpl_id, H5G_loc_t *root_loc) * super block to indicate that journaling is not turned on at * present. These initialization may be overridden shortly. */ - shared->mdc_jrnl_enabled = FALSE; - shared->mdc_jrnl_block_loc = HADDR_UNDEF; - shared->mdc_jrnl_block_len = 0; + shared->mdc_jnl_enabled = FALSE; + shared->mdc_jnl_magic = 0; + shared->mdc_jnl_file_name_len = 0; + (shared->mdc_jnl_file_name)[0] = '\0'; /* Get the shared file creation property list */ if(NULL == (c_plist = H5I_object(shared->fcpl_id))) @@ -744,17 +745,44 @@ H5F_super_read(H5F_t *f, hid_t dxpl_id, H5G_loc_t *root_loc) } /* end if */ else { - shared->mdc_jrnl_enabled = mdj_msg.mdc_jrnl_enabled; + shared->mdc_jnl_enabled = mdj_msg.mdc_jnl_enabled; - if ( shared->mdc_jrnl_enabled ) { + if ( shared->mdc_jnl_enabled ) { - shared->mdc_jrnl_block_loc = mdj_msg.mdc_jrnl_block_loc; - shared->mdc_jrnl_block_len = mdj_msg.mdc_jrnl_block_len; + shared->mdc_jnl_magic = mdj_msg.mdc_jnl_magic; + shared->mdc_jnl_file_name_len = mdj_msg.mdc_jnl_file_name_len; + + if ( shared->mdc_jnl_file_name_len <= 0 ) { + + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, \ + "journaling enabled, but journal file path empty?!?") + } + + if ( shared->mdc_jnl_file_name_len > + H5C2__MAX_JOURNAL_FILE_NAME_LEN ) { + + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, \ + "journal file path too long") + } + + HDstrncpy(shared->mdc_jnl_file_name, + mdj_msg.mdc_jnl_file_name, + mdj_msg.mdc_jnl_file_name_len + 1); + + if ( ( (shared->mdc_jnl_file_name) + [shared->mdc_jnl_file_name_len] != '\0' ) || + ( HDstrlen(shared->mdc_jnl_file_name) != + shared->mdc_jnl_file_name_len ) ) { + + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, \ + "bad journal file path and/or path len???") + } } else { - shared->mdc_jrnl_block_loc = HADDR_UNDEF; - shared->mdc_jrnl_block_len = 0; + shared->mdc_jnl_magic = 0; + shared->mdc_jnl_file_name_len = 0; + (shared->mdc_jnl_file_name)[0] = '\0'; } /* Reset metadata journaling config message */ @@ -765,9 +793,15 @@ H5F_super_read(H5F_t *f, hid_t dxpl_id, H5G_loc_t *root_loc) * closing the file (since this will be the only open object). */ f->nopen_objs++; - if(H5O_close(&ext_loc) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENFILE, FAIL, "unable to close superblock extension") + + if(H5O_close(&ext_loc) < 0) { + + HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENFILE, FAIL, \ + "unable to close superblock extension") + } + f->nopen_objs--; + } /* end if */ done: @@ -962,15 +996,35 @@ H5F_super_init(H5F_t *f, hid_t dxpl_id) HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to update driver info header message") } /* end if */ - /* check for journaling config data to store */ - if ( f->shared->mdc_jrnl_enabled ) { - struct H5O_mdj_msg_t mdj_conf; + /* One might expect us to check to see if journaling is enabled + * at this point, and write a metadata journaling message to the + * super block extension if it is. + * + * However, the cache has not been initialized at this point, + * so we don't know if we will be successful in creating the + * journal file (the journal file may already exist, or some + * directory on the journal path may not exist. + * + * Further, the cache should refuse to allow the file to open if + * it detects journaling in progress -- so marking journaling in + * progress here would introduce some complexities. + * status now + * + * Thus, don't write the metadata journaling message now. Instead, + * initialize the metadata journaling related fields to indicate + * that journaling is not in progress. If journaling is requested, + * we will write the metadata journaling message after we have + * successfully opened the journal file and started journaling. + * + * JRM -- 2/19/09 + */ + + f->shared->mdc_jnl_enabled = FALSE; + f->shared->mdc_jnl_magic = 0; + f->shared->mdc_jnl_file_name_len = 0; + (f->shared->mdc_jnl_file_name)[0] = '\0'; - mdj_conf.mdc_jrnl_enabled = f->shared->mdc_jrnl_enabled; - mdj_conf.mdc_jrnl_block_loc = f->shared->mdc_jrnl_block_loc; - mdj_conf.mdc_jrnl_block_len = f->shared->mdc_jrnl_block_len; - } /* Twiddle the number of open objects to avoid closing the file * (since this will be the only open object currently). @@ -1139,14 +1193,13 @@ done: } /* end H5F_super_write() */ - /*------------------------------------------------------------------------- * Function: H5F_super_write_mdj_msg * * If journaling is enabled, create a superblock extension * if necessary and then write the current contents of - * the mdc_jrnl_enabled, mdc_jrnl_block_loc, and + * the mdc_jnl_enabled, mdc_jrnl_block_loc, and * mdc_jrnl_block_len fields of the shared structure to the * mdj_msg in the superblock extention, overwriting the old * message if it exists. @@ -1162,6 +1215,17 @@ done: * * Programmer: John Mainzer * 3/3/08 + * + * Changes: JRM -- 2/17/09 + * Heavily re-worked the function to move the journal file + * name and journal file magic into the metadata journaling + * message. + * + * Note that this makes the metadata journaling message + * variable length, so we now delete any existing metadata + * journaling message, and then replace it with a new + * message if metadata journaling is enabled. + * *------------------------------------------------------------------------- */ herr_t @@ -1204,111 +1268,133 @@ H5F_super_write_mdj_msg(H5F_t *f, } } + /* The metadata journaling message is a variable length message. + * This raises the question of how to deal with any pre-existing + * message. + * + * While in theory we could try to re-size it, after looking through + * the code and talking to Quincey, it appears that the standard + * practice in such cases seems to be to delete the old message, + * and then replace it with a new message. + * + * Add to this the fact that the metadata journaling message + * should not exist unless journaling is enabled (or to put it + * another way, the message should never appear in a valid HDF5 + * file). + * + * Thus, here we check to see if a metadata jouraling message exists, + * and delete it if it does. If metadata data journaling is enabled, + * we will replace it with a new message shortly. + */ + tri_result = H5O_msg_exists(&ext_loc, H5O_MDJ_MSG_ID, dxpl_id); if ( tri_result < 0 ) { /* failure */ HGOTO_ERROR(H5E_SYSTEM, H5E_SYSERRSTR, FAIL, \ - "unable to open superblock extension?!?!"); + "unable to determine if metadata journaling message exists?!?!"); - } else if ( tri_result == 0 ) { - /* metadata journaling message doesn't exist */ + } else if ( tri_result == TRUE ) { - if ( f->shared->mdc_jrnl_enabled ) { + /* metadata journaling message exists -- delete it from the + * super block extension now. We will replace it later if + * metadata journaling is enabled. + */ - /* create a metadata journaling message and insert it in - * the superblock extension. - */ - mdj_msg.mdc_jrnl_enabled = f->shared->mdc_jrnl_enabled; - mdj_msg.mdc_jrnl_block_loc = f->shared->mdc_jrnl_block_loc; - mdj_msg.mdc_jrnl_block_len = f->shared->mdc_jrnl_block_len; + result = H5O_msg_remove(&ext_loc, + H5O_MDJ_MSG_ID, + H5O_ALL, + /* the next parameter is the "adj_link" parameter, which is + * boolean. Unfortunately, its meaning is not documented + * in the code. The value gets stuffed into an instance of + * H5O_iter_rm_t, and then passed along somehow to a function + * whose address appears to be picked out of a table somewhere. + * + * The documentation on the adj_link field of H5O_iter_rm_t + * simply says that the value specifies "Whether to adjust + * links when removing messages" -- but unfortunately, I + * don't know what a "link" is in this context. + * + * Bottom line is that after spending over an hour dredging + * through the code, I haven't a clue as to what the value + * of this parameter should be. We will set it to FALSE and + * see if anything blows up. + * + * JRM -- 3/5/08 + */ + FALSE, + dxpl_id); - result = H5O_msg_create(&ext_loc, - H5O_MDJ_MSG_ID, - H5O_MSG_FLAG_DONTSHARE, - H5O_UPDATE_TIME, - &mdj_msg, - dxpl_id); + } else if ( tri_result != FALSE ) { - if ( result < 0 ) { + HGOTO_ERROR(H5E_SYSTEM, H5E_SYSERRSTR, FAIL, \ + "unexpected return value from H5O_msg_exists()"); + } - HGOTO_ERROR(H5E_SYSTEM, H5E_SYSERRSTR, FAIL, \ - "unable to add mdj_msg to superblock extension?!?!"); - } + if ( f->shared->mdc_jnl_enabled ) { - } else { + /* create a metadata journaling message and insert it in + * the superblock extension. + */ + mdj_msg.mdc_jnl_enabled = f->shared->mdc_jnl_enabled; + mdj_msg.mdc_jnl_magic = f->shared->mdc_jnl_magic; + mdj_msg.mdc_jnl_file_name_len = f->shared->mdc_jnl_file_name_len; - /* do nothing */ - } + if ( f->shared->mdc_jnl_file_name_len == 0 ) { - } else { - /* metadata journaling message exists */ - - if ( f->shared->mdc_jrnl_enabled ) { - - /* overwrite the old metadata journaling message with a - * new one in the superblock extension. - */ - mdj_msg.mdc_jrnl_enabled = f->shared->mdc_jrnl_enabled; - mdj_msg.mdc_jrnl_block_loc = f->shared->mdc_jrnl_block_loc; - mdj_msg.mdc_jrnl_block_len = f->shared->mdc_jrnl_block_len; - - result = H5O_msg_write(&ext_loc, - H5O_MDJ_MSG_ID, - H5O_MSG_FLAG_DONTSHARE, - H5O_UPDATE_TIME, - &mdj_msg, - dxpl_id); - - if ( result < 0 ) { - - HGOTO_ERROR(H5E_SYSTEM, H5E_SYSERRSTR, FAIL, \ - "unable to overwrite mdj_msg in superblock extension?!?!"); - } - - - } else { - - /* delete the old metadata journaling message from the - * superblock extension. - */ - - result = H5O_msg_remove(&ext_loc, - H5O_MDJ_MSG_ID, - H5O_ALL, - /* the next parameter is the "adj_link" parameter, which is - * boolean. Unfortunately, its meaning is not documented - * in the code. The value gets stuffed into an instance of - * H5O_iter_rm_t, and then passed along somehow to a funcition - * whose address appears to be picked out of a table somewhere. - * - * The documentation on the adj_link field of H5O_iter_rm_t - * simply says that the value specifies "Whether to adjust - * links when removing messages" -- but unfortunately, I - * don't know what a "link" is in this context. - * - * Bottom line is that after spending over an hour dredging - * through the code, I haven't a clue as to what the value - * of this parameter should be. We will set it to FALSE and - * see if anything blows up. - * - * JRM -- 3/5/08 - */ - FALSE, - dxpl_id); - } + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, \ + "journaling enabled, but journal file path empty?!?") - } + } + + if ( f->shared->mdc_jnl_file_name_len > + H5C2__MAX_JOURNAL_FILE_NAME_LEN ) { + + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, \ + "journal file path too long?!?") + + } + + HDstrncpy(mdj_msg.mdc_jnl_file_name, + f->shared->mdc_jnl_file_name, + f->shared->mdc_jnl_file_name_len + 1); + + if ( ( (mdj_msg.mdc_jnl_file_name)[mdj_msg.mdc_jnl_file_name_len] + != '\0' ) || + ( HDstrlen(mdj_msg.mdc_jnl_file_name) != + mdj_msg.mdc_jnl_file_name_len ) ) { + + HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, \ + "bad journal file path and/or path len???") + } + + result = H5O_msg_create(&ext_loc, + H5O_MDJ_MSG_ID, + H5O_MSG_FLAG_DONTSHARE, + H5O_UPDATE_TIME, + &mdj_msg, + dxpl_id); + + if ( result < 0 ) { + + HGOTO_ERROR(H5E_SYSTEM, H5E_SYSERRSTR, FAIL, \ + "unable to add mdj_msg to superblock extension?!?!"); + } + + } /* Close the extension. Twiddle the number of open objects to avoid * closing the file (since this may be the only open object). */ + f->nopen_objs++; + if(H5O_close(&ext_loc) < 0) { HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENFILE, FAIL, "unable to close superblock extension") } + f->nopen_objs--; done: diff --git a/src/H5Ochunk.c b/src/H5Ochunk.c index 634c628..813006e 100644 --- a/src/H5Ochunk.c +++ b/src/H5Ochunk.c @@ -234,8 +234,10 @@ H5O_chunk_unprotect(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_chunk_proxy_t *chk_p HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty") } /* end else/if */ else + { /* Sanity check */ HDassert(0 && "Unknown chunk proxy flag(s)?!?"); + } /* Free fake chunk proxy */ H5FL_FREE(H5O_chunk_proxy_t, chk_proxy); diff --git a/src/H5Omdj_msg.c b/src/H5Omdj_msg.c index 044ce4a..6ba1774 100644 --- a/src/H5Omdj_msg.c +++ b/src/H5Omdj_msg.c @@ -20,29 +20,34 @@ * John Mainzer * * Purpose: A message detailing whether metadata jouraling is enabled, - * and if so, the base address in file and length of the block - * that contains the journaling configuration data. + * and if so, the journal file magic and journal file path. + * + * Note that the size of this message is variable. * * The mdj_msg only appears in the superblock extension. * * Modifications: * - * None. + * Re-worked message to include the journal file name and + * magic, instead of simply containing a pointer to a + * journal configuration block containing this data. * *------------------------------------------------------------------------- */ -#define H5O_PACKAGE /*suppress error about including H5Opkg */ +#define H5O_PACKAGE /* suppress error about including H5Opkg */ -#include "H5private.h" /* Generic Functions */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5Opkg.h" /* Object headers */ -#include "H5MMprivate.h" /* Memory management */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Opkg.h" /* Object headers */ +#include "H5MMprivate.h" /* Memory management */ -#define MDJ_MSG_LEN(f) ( 1 + /* Version number */ \ - 2 + /* flags */ \ - H5F_SIZEOF_ADDR(f) + /* addr of journal config block */ \ - H5F_SIZEOF_SIZE(f) ) /* journal config block len */ +#define MDJ_MSG_LEN(f, pathlen) \ + ( 1 + /* Version number */ \ + 2 + /* flags */ \ + 4 + /* magic -- sizeof(int32_t) */ \ + 4 + /* jnl file path len - sizeof(int32_t) */ \ + pathlen + 1 ) /* jnl file path */ static void * H5O_mdj_msg_decode(H5F_t UNUSED *f, hid_t UNUSED dxpl_id, @@ -95,12 +100,6 @@ const H5O_msg_class_t H5O_MSG_MDJ_CONF[1] = {{ H5O_mdj_msg_debug /* debug the message */ }}; - -/* Current version of the metadata journaling configuration information */ -#define H5O_MDJ_CONF_VERSION 0 - -#define MDJ_MSG__JOURNALING_ENABLED_FLAG 0x0001 - /*------------------------------------------------------------------------- * Function: H5O_mdj_msg_decode @@ -123,8 +122,12 @@ H5O_mdj_msg_decode(H5F_t *f, unsigned UNUSED mesg_flags, const uint8_t *p) { + char ch; uint16_t flags = 0; /* packed boolean fields */ - H5O_mdj_msg_t *mesg; /* Native message */ + int i; + int32_t journal_magic; /* magic number -- if defined */ + int32_t path_len; /* journal file path length */ + H5O_mdj_msg_t *mesg; /* Native message */ void *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_mdj_msg_decode) @@ -142,7 +145,8 @@ H5O_mdj_msg_decode(H5F_t *f, /* Allocate space for message */ - if( NULL == ( mesg = H5MM_calloc(sizeof(H5O_mdj_msg_t)))) { + if ( NULL == + (mesg = (H5O_mdj_msg_t *)H5MM_calloc(sizeof(H5O_mdj_msg_t))) ) { HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, \ "memory allocation failed for metadata journaling message."); @@ -154,21 +158,51 @@ H5O_mdj_msg_decode(H5F_t *f, if ( (flags & MDJ_MSG__JOURNALING_ENABLED_FLAG) != 0 ) { - mesg->mdc_jrnl_enabled = TRUE; + mesg->mdc_jnl_enabled = TRUE; } else { - mesg->mdc_jrnl_enabled = FALSE; + mesg->mdc_jnl_enabled = FALSE; + + } + + + /* get the journal file magic number */ + INT32DECODE(p, journal_magic); + + mesg->mdc_jnl_magic = journal_magic; + + + /* get the journal file path length */ + INT32DECODE(p, path_len); + + if ( path_len > H5C2__MAX_JOURNAL_FILE_NAME_LEN ) { + HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "path length too big.") } - /* retrieve the journal block location */ + mesg->mdc_jnl_file_name_len = (size_t)path_len; - H5F_addr_decode(f, &p, &(mesg->mdc_jrnl_block_loc)); - /* retrieve the journal block length */ + /* copy out the journal file path -- check length in passing. + * + * we could probably do this faster with a memcpy(), but this + * operation happens very infrequently, and doing it this way + * adds a bit of sanity checking. + */ + i = 0; + do { - H5F_DECODE_LENGTH(f, p, mesg->mdc_jrnl_block_len); + ch = (char)(*p++); + mesg->mdc_jnl_file_name[i++] = ch; + + } while ( ( ch != '\0' ) && ( i <= path_len ) ); + + if ( ( ch != '\0' ) || ( i != path_len + 1 ) ) { + + HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, \ + "bad path and/or path len") + } /* Set return value */ ret_value = (void *)mesg; @@ -201,6 +235,8 @@ H5O_mdj_msg_encode(H5F_t *f, { const H5O_mdj_msg_t *mesg = (const H5O_mdj_msg_t *)_mesg; uint16_t flags = 0; + int32_t magic; + int32_t path_len; herr_t ret_value; FUNC_ENTER_NOAPI_NOINIT(H5O_mdj_msg_encode) @@ -210,28 +246,40 @@ H5O_mdj_msg_encode(H5F_t *f, HDassert(p); HDassert(mesg); - /* this error check exists to keep the compiler happy */ if ( ( f == NULL ) || ( p == NULL ) || ( mesg == NULL ) ) { HGOTO_ERROR(H5E_SYSTEM, H5E_SYSERRSTR, FAIL, "Bad params on entry."); } + if ( mesg->mdc_jnl_file_name_len > H5C2__MAX_JOURNAL_FILE_NAME_LEN ) { + + HGOTO_ERROR(H5E_SYSTEM, H5E_SYSERRSTR, FAIL, \ + "Bad params on entry -- path len too long."); + } + /* setup the flags */ - if ( mesg->mdc_jrnl_enabled ) { + if ( mesg->mdc_jnl_enabled ) { flags |= MDJ_MSG__JOURNALING_ENABLED_FLAG; } - /* Store version, flags, internal_loc, path_len, & path buffer */ + magic = mesg->mdc_jnl_magic; + + path_len = (int32_t)(mesg->mdc_jnl_file_name_len); + + /* Store version, flags, magic, path_len, & path */ *p++ = H5O_MDJ_CONF_VERSION; UINT16ENCODE(p, flags); - H5F_addr_encode(f, &p, mesg->mdc_jrnl_block_loc); - - H5F_ENCODE_LENGTH(f, p, mesg->mdc_jrnl_block_len); + INT32ENCODE(p, magic); + + INT32ENCODE(p, path_len); + + HDmemcpy(p, mesg->mdc_jnl_file_name, path_len + 1); + p += path_len + 1; done: @@ -267,6 +315,11 @@ H5O_mdj_msg_copy(const void *_mesg, void *_dest) /* Sanity check */ HDassert(mesg); + if ( mesg->mdc_jnl_file_name_len > H5C2__MAX_JOURNAL_FILE_NAME_LEN ) { + + HGOTO_ERROR(H5E_SYSTEM, H5E_SYSERRSTR, FAIL, "path len too long."); + } + if ( ( ! dest ) && ( NULL == (dest = H5MM_malloc(sizeof(H5O_mdj_msg_t))) ) ) { @@ -276,9 +329,41 @@ H5O_mdj_msg_copy(const void *_mesg, void *_dest) } /* now copy the message */ - dest->mdc_jrnl_enabled = mesg->mdc_jrnl_enabled; - dest->mdc_jrnl_block_loc = mesg->mdc_jrnl_block_loc; - dest->mdc_jrnl_block_len = mesg->mdc_jrnl_block_len; + dest->mdc_jnl_enabled = mesg->mdc_jnl_enabled; + dest->mdc_jnl_magic = mesg->mdc_jnl_magic; + dest->mdc_jnl_file_name_len = mesg->mdc_jnl_file_name_len; + + /* copy the journal file path -- check length in passing. + * + * we could probably do this faster with a memcpy(), but this + * operation happens very infrequently, and doing it this way + * adds a bit of sanity checking. + */ + if ( mesg->mdc_jnl_file_name_len == 0 ) { + + (dest->mdc_jnl_file_name)[0] = '\0'; + + } else { + + char ch; + int i = 0; + size_t path_len; + + path_len = mesg->mdc_jnl_file_name_len; + + do { + + ch = (mesg->mdc_jnl_file_name)[i]; + (dest->mdc_jnl_file_name)[i++] = ch; + + } while ( ( ch != '\0' ) && ( i <= path_len ) ); + + if ( ( ch != '\0' ) || ( i != path_len + 1 ) ) { + + HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, \ + "bad path and/or path len???") + } + } /* Set return value */ ret_value = dest; @@ -314,10 +399,12 @@ H5O_mdj_msg_size(const H5F_t *f, FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_mdj_msg_size) /* Sanity check */ - HDassert(f); - HDassert(mesg); + HDassert( f ); + HDassert( mesg ); + HDassert( mesg->mdc_jnl_file_name_len >= 0 ); + + FUNC_LEAVE_NOAPI(MDJ_MSG_LEN(f, mesg->mdc_jnl_file_name_len)) - FUNC_LEAVE_NOAPI(MDJ_MSG_LEN(f)) } /* end H5O_mdj_msg_size() */ @@ -348,11 +435,13 @@ H5O_mdj_msg_reset(void *_mesg) HDassert(mesg); /* reset */ - mesg->mdc_jrnl_enabled = FALSE; - mesg->mdc_jrnl_block_loc = HADDR_UNDEF; - mesg->mdc_jrnl_block_len = 0; + mesg->mdc_jnl_enabled = FALSE; + mesg->mdc_jnl_magic = 0; + mesg->mdc_jnl_file_name_len = 0; + (mesg->mdc_jnl_file_name)[0] = '\0'; FUNC_LEAVE_NOAPI(SUCCEED) + } /* H5O_mdj_msg_reset() */ @@ -389,17 +478,22 @@ H5O_mdj_msg_debug(H5F_t UNUSED *f, HDassert(fwidth >= 0); HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth, - "mdc_jrnl_enabled:", - (int)(mesg->mdc_jrnl_enabled)); + "mdc_jnl_enabled:", + (int)(mesg->mdc_jnl_enabled)); - HDfprintf(stream, "%*s%-*s %a\n", indent, "", fwidth, - "mdc_jrnl_bloc_loc:", - mesg->mdc_jrnl_block_loc); + HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth, + "mdc_jnl_magic:", + (int)(mesg->mdc_jnl_magic)); HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth, - "mdc_jrnl_block_len:", - (int)(mesg->mdc_jrnl_block_len)); + "mdc_jnl_file_name_len:", + (int)(mesg->mdc_jnl_file_name_len)); + + HDfprintf(stream, "%*s%-*s \"%s\"\n", indent, "", fwidth, + "mdc_jnl_file_name:", + (char *)(mesg->mdc_jnl_file_name)); FUNC_LEAVE_NOAPI(SUCCEED) + } /* end H5O_mdj_msg_debug() */ diff --git a/src/H5Omessage.c b/src/H5Omessage.c index 3c29c24..9bfe756 100644 --- a/src/H5Omessage.c +++ b/src/H5Omessage.c @@ -2012,15 +2012,22 @@ H5O_copy_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx, HDassert(mesg); /* Protect chunk */ - if(NULL == (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, idx_msg->chunkno))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk") + if ( NULL == + (chk_proxy = H5O_chunk_protect(f, dxpl_id, oh, idx_msg->chunkno)) ) { + + HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, \ + "unable to load object header chunk") + } /* Reset existing native information for the header's message */ H5O_msg_reset_real(type, idx_msg->native); /* Copy the native object for the message */ - if(NULL == (idx_msg->native = (type->copy)(mesg, idx_msg->native))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to copy message to object header") + if ( NULL == (idx_msg->native = (type->copy)(mesg, idx_msg->native)) ) { + + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, \ + "unable to copy message to object header") + } /* Update the message flags */ idx_msg->flags = mesg_flags; diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index 2b3710c..4cac29d 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -509,30 +509,44 @@ typedef uint32_t H5O_refcount_t; /* Contains # of links to object, if >1 /* * Metadata journaling message * - * Information on whether are being journaled, and if so, the size and - * location of the on disk block containing the deatils of the journaling. + * Information on whether are being journaled, and if so, the magic + * number (if defined) and path to the journal file. * (Data structure in memory) * * The fields of the H5O_mdj_msg_t structure are discussed individually * below: * - * mdc_jrnl_enabled: Boolean flag indicating whether metadata journaling + * mdc_jnl_enabled: Boolean flag indicating whether metadata journaling * is currently enabled. * - * mdc_jrnl_block_loc: haddr_t containing the base address of the - * of the block containing the configuration details of the - * journaling. + * mdc_jnl_magic: Randomly selected int32_t used to reduce the possibility + * of running the wrong journal on an HDF5 file. The basic idea is + * to pick a random number, store it in both the HDF5 file and the + * journal file, and then refuse to run the journal unless the numbers + * match. * - * mdc_jrnl_block_len: hsize_t containing the size of the buffer needed to - * contain the journaling configuration block + * The value of this field is undefined unless mdc_jnl_enabled is TRUE. * - * If the journal is internal, this field must be NULL. + * mdc_jnl_file_name_len: Length of the journal file name. + * + * The value of this field is undefined unless mdc_jnl_enabled is TRUE. + * + * mdc_jnl_file_name: Array of char of length + * H5C2__MAX_JOURNAL_FILE_NAME_LEN + 1 used to store the journal + * file path. + * + * The value of this field is undefined unless mdc_jnl_enabled is TRUE. */ + +#define H5O_MDJ_CONF_VERSION 0 +#define MDJ_MSG__JOURNALING_ENABLED_FLAG 0x0001 + typedef struct H5O_mdj_msg_t { - hbool_t mdc_jrnl_enabled; - haddr_t mdc_jrnl_block_loc; - hsize_t mdc_jrnl_block_len; + hbool_t mdc_jnl_enabled; + int32_t mdc_jnl_magic; + size_t mdc_jnl_file_name_len; + char mdc_jnl_file_name[H5C2__MAX_JOURNAL_FILE_NAME_LEN + 1]; } H5O_mdj_msg_t; |