diff options
author | John Mainzer <mainzer@hdfgroup.org> | 2008-02-25 10:01:56 (GMT) |
---|---|---|
committer | John Mainzer <mainzer@hdfgroup.org> | 2008-02-25 10:01:56 (GMT) |
commit | 738078322dd2b189ec1233c9ea59f218c2008740 (patch) | |
tree | 81ac2180a5f6eed1d65198de2abf2c6569bf48bb | |
parent | cd571e4a45e5af71ae608388141e6b28a16f8171 (diff) | |
download | hdf5-738078322dd2b189ec1233c9ea59f218c2008740.zip hdf5-738078322dd2b189ec1233c9ea59f218c2008740.tar.gz hdf5-738078322dd2b189ec1233c9ea59f218c2008740.tar.bz2 |
[svn-r14642] Folded initial version of Mike M's journal entry logging code into
the journaling branch. Added several new errors, and made many edits
to Mike's code (don't worry Mike -- changes I made were on items I
neglected to discuss with you).
Serial test on Phoenix only.
-rw-r--r-- | src/H5C2journal.c | 1180 | ||||
-rw-r--r-- | src/H5C2pkg.h | 134 | ||||
-rw-r--r-- | src/H5C2private.h | 51 | ||||
-rw-r--r-- | src/H5Edefin.h | 4 | ||||
-rw-r--r-- | src/H5Einit.h | 20 | ||||
-rw-r--r-- | src/H5Epubgen.h | 8 | ||||
-rw-r--r-- | src/H5Eterm.h | 8 | ||||
-rw-r--r-- | src/H5err.txt | 5 | ||||
-rw-r--r-- | test/Makefile.am | 2 | ||||
-rw-r--r-- | test/Makefile.in | 57 | ||||
-rw-r--r-- | test/cache2_journal.c | 426 |
11 files changed, 1867 insertions, 28 deletions
diff --git a/src/H5C2journal.c b/src/H5C2journal.c index bb64f7f..515cd61 100644 --- a/src/H5C2journal.c +++ b/src/H5C2journal.c @@ -46,7 +46,7 @@ #include "H5C2pkg.h" /* Cache */ /**************************************************************************/ -/********************** super block message support ***********************/ +/**************** super block message support declarations ****************/ /**************************************************************************/ static void * H5O_mdj_conf_decode(H5F_t UNUSED *f, @@ -107,6 +107,11 @@ const H5O_msg_class_t H5O_MSG_MDJ_CONF[1] = {{ #define MDJ_CONF__JOURNALING_ENABLED_FLAG 0x0001 #define MDJ_CONF__JOURNAL_IS_EXTERNAL_FLAG 0x0002 + +/**************************************************************************/ +/***************** super block message support functions ******************/ +/**************************************************************************/ + /*------------------------------------------------------------------------- * Function: H5O_mdj_conf_decode @@ -517,3 +522,1176 @@ H5O_mdj_conf_debug(H5F_t UNUSED *f, FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5O_mdj_conf_debug() */ + + +/**************************************************************************/ +/********************** journal file management code **********************/ +/**************************************************************************/ + +/****************************************************************************** + * + * Function: H5C2_jb__flush_full_buffers + * + * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> + * Wednesday, February 6, 2008 + * + * Purpose: Flush the specified number of buffers to disk, starting + * from the buffer indexed by struct_ptr->get. + * + * Returns: SUCCEED on success. + * + ******************************************************************************/ + +herr_t +H5C2_jb__flush_full_buffers(H5C2_jbrb_t * struct_ptr) +{ + int result; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5C2_jb__flush_full_buffers, 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 */ + /* code */ + + /* flush all full, dirtied journal buffers to disk */ + if (struct_ptr->get < struct_ptr->put) { + + /* can write solid chunk from get up to, but not + * including, put + */ + HDwrite(struct_ptr->journal_file_fd, + (*struct_ptr->buf)[struct_ptr->get], + (struct_ptr->put - struct_ptr->get) * struct_ptr->buf_size); + + struct_ptr->bufs_in_use -= (struct_ptr->put - struct_ptr->get); + + } else { + + /* write from get through end of buffer */ +/* JRM: need to check return on this call, and flag an error if it fails */ + 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 ( result == -1 ) { + + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, \ + "Journal file write failed.") + } + + struct_ptr->bufs_in_use -= (struct_ptr->num_bufs - struct_ptr->get); + + /* write from start of buffer up to, but not including, put */ + /* note that when get = put = 0, the full ring buffer has + * already written at this point, and this write does nothing + */ + result = HDwrite(struct_ptr->journal_file_fd, + (*struct_ptr->buf)[0], + (struct_ptr->put) * struct_ptr->buf_size); + + if ( result == -1 ) { + + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, \ + "Journal file write failed.") + } + + struct_ptr->bufs_in_use -= struct_ptr->put; + } + + HDassert(struct_ptr->bufs_in_use <= 1); + + /* perform a sync to ensure everything gets to disk before continuing */ + if ( fsync(struct_ptr->journal_file_fd) < 0 ) { + + HGOTO_ERROR(H5E_IO, H5E_SYNCFAIL, FAIL, "Jounal file sync failed.") + + } /* end if */ + + /* update get pointer */ + struct_ptr->get = struct_ptr->put; + + /* record last transaction number that made it to disk */ + if (struct_ptr->put == 0) { + + struct_ptr->last_trans_on_disk = + (*struct_ptr->trans_on_disk_record)[struct_ptr->num_bufs - 1]; + + } else { + + struct_ptr->last_trans_on_disk = + (*struct_ptr->trans_on_disk_record)[struct_ptr->put - 1]; + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5C2_jb__flush_full_buffers */ + + +/****************************************************************************** + * + * Function: H5C2_jb__flush + * + * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> + * Wednesday, February 6, 2008 + * + * Purpose: Verify that there is no transaction in progress. Then + * flush all journal entries in the journal buffers to the + * journal file. Do not return until all entries are on + * disk. + * + * Returns: SUCCEED on success. + * + ******************************************************************************/ + +herr_t +H5C2_jb__flush(H5C2_jbrb_t * struct_ptr) +{ + int result; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5C2_jb__flush, FAIL) + + /* Check Arguments */ + HDassert(struct_ptr); + HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); + + /* Check if transaction is in progress */ + + if (struct_ptr->trans_in_prog != FALSE) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Attempt to flush buffers with transaction in progress.") + } /* end if */ + + /* flush all full, dirtied journal buffers to disk */ + if (struct_ptr->get < struct_ptr->put) { + + /* 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); + + if ( result == -1 ) { + + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, \ + "Journal file write failed.") + } + + struct_ptr->bufs_in_use -= (struct_ptr->put - struct_ptr->get); + + } else if ( ( struct_ptr->get == struct_ptr->put ) && + ( struct_ptr->cur_buf_free_space != 0 ) ) { + + /* do nothing for now ... this is the case when no buffer is full. */ + + } else { + /* 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 ( result == -1 ) { + + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, \ + "Journal file write failed.") + } + + struct_ptr->bufs_in_use -= (struct_ptr->num_bufs - struct_ptr->get); + + /* write from start of buffer up to, but not including, put */ + /* note that when get = put = 0, the full ring buffer has already + * written at this point, and this write does nothing + */ + result = HDwrite(struct_ptr->journal_file_fd, + (*struct_ptr->buf)[0], + (struct_ptr->put) * struct_ptr->buf_size); + + if ( result == -1 ) { + + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, \ + "Journal file write failed.") + } + + struct_ptr->bufs_in_use -= struct_ptr->put; + } + + /* flush partially filled portion of current journal buffer to disk */ + if ( ( struct_ptr->cur_buf_free_space != 0 ) && + ( struct_ptr->cur_buf_free_space != struct_ptr->buf_size ) ) { + + result = HDwrite(struct_ptr->journal_file_fd, + (*struct_ptr->buf)[struct_ptr->put], + struct_ptr->buf_size - struct_ptr->cur_buf_free_space); + + if ( result == -1 ) { + + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, \ + "Journal file write failed.") + } + + struct_ptr->bufs_in_use--; + } + + HDassert(struct_ptr->bufs_in_use == 0); + + /* perform sync to ensure everything gets to disk before returning */ + if ( fsync(struct_ptr->journal_file_fd) < 0 ) { + + HGOTO_ERROR(H5E_IO, H5E_SYNCFAIL, FAIL, "Jounal file sync failed.") + } /* end if */ + + /* MIKE: optimization note: don't reset to top of ring buffer. + * instead, keep filling out current buffer so we can keep writes + * on block boundaries. + */ + 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->head = (*struct_ptr->buf)[0]; + struct_ptr->put = 0; + + /* update get pointer */ + struct_ptr->get = struct_ptr->put; + + /* record last transaction number that made it to disk */ + if (struct_ptr->put == 0) { + + struct_ptr->last_trans_on_disk = + (*struct_ptr->trans_on_disk_record)[struct_ptr->num_bufs - 1]; + + } else { + + struct_ptr->last_trans_on_disk = + (*struct_ptr->trans_on_disk_record)[struct_ptr->put - 1]; + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5C2_jb__flush */ + + +/****************************************************************************** + * + * Function: H5C2_jb__write_to_buffer + * + * 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. + * + * Returns: SUCCEED on success. + * + ******************************************************************************/ + +herr_t +H5C2_jb__write_to_buffer(H5C2_jbrb_t * struct_ptr, + size_t size, + const char * data) +{ + herr_t ret_value = SUCCEED; + + 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(strlen(data) == size); + HDassert(struct_ptr->rb_free_space <= + struct_ptr->num_bufs * struct_ptr->buf_size); + HDassert(struct_ptr->rb_free_space > 0); /* JOHN: will remain true in interesting ways */ + + /* If the data size exceeds the bounds of the ring buffer's allocated + * memory, loop around to top + */ + if (size >= struct_ptr->rb_free_space) { + + while (size >= struct_ptr->rb_free_space) { + + /* Assertions */ + HDassert(size != 0); + HDassert(strlen(data) >= struct_ptr->rb_free_space); + + /* fill up remaining space in the ring buffer */ + memcpy(struct_ptr->head, data, struct_ptr->rb_free_space); + + /* move head to point to start of ring buffer */ + struct_ptr->head = (*struct_ptr->buf)[0]; + + /* 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; + + /* 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_free_space; + + /* update the data pointer to point to the remaining data to be + * written + */ + data = &data[struct_ptr->rb_free_space]; + + /* update the amount of space that is available to write to */ + struct_ptr->rb_free_space = + 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 */ + memcpy(struct_ptr->head, data, size); + + /* update head pointer */ + struct_ptr->head = &struct_ptr->head[size]; + + /* update put index */ + struct_ptr->put += + (size-struct_ptr->cur_buf_free_space)/(struct_ptr->buf_size) + 1; + + /* update current buffer usage */ + struct_ptr->cur_buf_free_space = + struct_ptr->rb_free_space - 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++; + } + + /* 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 ring buffer usage */ + struct_ptr->rb_free_space -= 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 */ + memcpy(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 current buffer usage */ + struct_ptr->cur_buf_free_space -= size; + + /* update ring buffer usage */ + struct_ptr->rb_free_space -= size; + + /* 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; + + } else { + struct_ptr->put = 0; + struct_ptr->head = (*struct_ptr->buf)[0]; + struct_ptr->rb_free_space = + struct_ptr->buf_size * struct_ptr->num_bufs; + } + + if ( H5C2_jb__flush_full_buffers(struct_ptr) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__flush_full_buffers() failed.\n") + } + + struct_ptr->cur_buf_free_space = struct_ptr->buf_size; + } + + } /* end else */ + + HDassert(struct_ptr->bufs_in_use <= struct_ptr->num_bufs); + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5C2_jb__write_to_buffer */ + + +/****************************************************************************** + * + * Function: H5C2_jb__init + * + * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> + * Tuesday, February 5, 2008 + * + * Purpose: Initialize the supplied instance of H5C2_jbrb_t as + * specified by the buf_size and num_bufs fields. Open the + * journal file whose name is supplied in journal_file_name + * for either synchronous or asynchronous I/O as specified + * by use_aio. + * + * Returns: SUCCEED on success. + * + ******************************************************************************/ + +herr_t +H5C2_jb__init(H5C2_jbrb_t * struct_ptr, + char * HDF5_file_name, + char * journal_file_name, + size_t buf_size, + int num_bufs, + hbool_t use_aio, + hbool_t human_readable) +{ + char temp[150]; + int i; + herr_t ret_value = SUCCEED; + + 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); + + /* Open journal file */ + struct_ptr->journal_file_fd = + open(journal_file_name, O_WRONLY|O_CREAT|O_EXCL, 0777); + + if ( struct_ptr->journal_file_fd == -1) { + + /* JRM -- why are we trying to close a file we have just failed to + * create? Commenting this out for now -- put it back in + * if there is a good reason to. + */ + /* HDclose(struct_ptr->journal_file_fd); */ + HGOTO_ERROR(H5E_FILE, H5E_CANTCREATE, FAIL, \ + "Can't create journal file. Does it already exist?") + } /* end if */ + + /* Initialize Fields of H5C2_jbrb_t structure */ + struct_ptr->jname = 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->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 *)); + + if ( struct_ptr->buf == NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "allocation of buf pointer array failed."); + } /* end if */ + + /* Allocate space for journal buffers */ + (*struct_ptr->buf)[0] = + H5MM_malloc(struct_ptr->buf_size * struct_ptr->num_bufs); + + if ( (*struct_ptr->buf)[0] == NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "allocation of buffers failed."); + } /* end if */ + + /* Allocate space for the purposes of tracking the last + * transaction on disk + */ + struct_ptr->trans_on_disk_record = + H5MM_malloc(struct_ptr->num_bufs * sizeof(unsigned long)); + + if ( struct_ptr->trans_on_disk_record == NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "allocation of trans_on_disk_record failed."); + } /* end if */ + + /* Initialize last transaction on disk record array */ + for (i=0; i<struct_ptr->num_bufs; i++) + { + (*struct_ptr->trans_on_disk_record)[i] = 0; + } + + /* Make journal buffer pointers point to the right location in + * chunk of allocated memory above + */ + for (i=1; i<struct_ptr->num_bufs; i++) + { + (*struct_ptr->buf)[i] = + &((*struct_ptr->buf)[0])[i * struct_ptr->buf_size]; + } + + /* Define head pointer to point at where we are writing to in the buffer */ + struct_ptr->head = (*struct_ptr->buf)[struct_ptr->put]; + + /* Format the header message into a temporary buffer */ + HDsnprintf(temp, + (size_t)150, + "0 ver_num %ld target_file_name %s creation_date %s human_readable %d\n", + struct_ptr->jvers, + struct_ptr->hdf5_file_name, + __DATE__, + struct_ptr->human_readable); + + /* Write the header message into the ring buffer */ + if ( H5C2_jb__write_to_buffer(struct_ptr, strlen(temp), temp ) < 0) { + + 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 is next in + * sequence. 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, + unsigned long trans_num) + +{ + char temp[150]; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5C2_jb__start_transaction, FAIL) + + /* 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 */ + + /* Verify that the supplied transaction number is next in sequence */ + if ( (struct_ptr->cur_trans + 1) != 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 ) { + + HDsnprintf(temp, + (size_t)150, + "0 ver_num %ld target_file_name %s creation_date %s human_readable %d\n", + struct_ptr->jvers, + struct_ptr->hdf5_file_name, + __DATE__, + struct_ptr->human_readable); + + if ( H5C2_jb__write_to_buffer(struct_ptr, strlen(temp), temp) < 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 %ld\n", trans_num); + if ( H5C2_jb__write_to_buffer(struct_ptr, strlen(temp), temp) < 0 ) { + + 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; + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5C2_jb__start_transaction */ + + +/****************************************************************************** + * + * Function: H5C2_jb__journal_entry + * + * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> + * Wednesday, February 6, 2008 + * + * Purpose: Verify that the specified transaction is open. Then + * construct a journal entry recording the supplied base + * address, length, and body, and write it to the current + * journal buffer. + * + * Returns: SUCCEED on success. + * + ******************************************************************************/ + +herr_t +H5C2_jb__journal_entry(H5C2_jbrb_t * struct_ptr, + unsigned long trans_num, + haddr_t base_addr, + size_t length, + char * body) +{ + char * temp = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5C2_jb__journal_entry, FAIL) + + /* Check Arguments */ + HDassert(struct_ptr); + HDassert(body); + 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 ) ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Transaction not in progress or bad transaction number.") + } /* end if */ + + if ( (temp = H5MM_malloc(length + 100)) == NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "allocation of assembly buffer failed."); + } + + /* Write journal entry */ + /* JRM -- Modified to printf base addr in HEX + * -- Must check with Quincey about using the %a option in + * format string for haddr_t. Casting to unsigned long + * for now. + */ + HDsnprintf(temp, + (size_t)(length + 100), + "2 trans_num %ld length %d base_addr Ox%lx body ", + trans_num, + length, + (unsigned long)base_addr); /* <== fix this */ + + if ( H5C2_jb__write_to_buffer(struct_ptr, strlen(temp), temp) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__write_to_buffer() failed.\n") + } /* end if */ + + /* JRM -- the buffer will contain binary -- need to conver to hex */ + if ( H5C2_jb__write_to_buffer(struct_ptr, length, body) < 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") < 0) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__write_to_buffer() failed.\n") + } /* end if */ + + /* Indicate that at least one journal entry has been written under + * this transaction + */ + if ( struct_ptr->jentry_written == FALSE ) { + + struct_ptr->jentry_written = TRUE; + } + +done: + + if ( temp != NULL ) + { + temp = H5MM_xfree(temp); + if ( temp != NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "free of assembly buffer failed."); + } + } + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5C2_jb__journal_entry */ + + +/****************************************************************************** + * + * 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, + unsigned long trans_num) +{ + char temp[25]; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5C2_jb__end_transaction, FAIL) + + /* Check Arguments */ + 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 ) ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Transaction not in progress or bad transaction number.") + } /* end if */ + + /* Verify that at least one journal entry has been written under + * the current transaction + */ + if ( struct_ptr->jentry_written != TRUE ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Empty transaction -- at least one journal entry required.") + } /* end if */ + + /* Write end transaction message */ + HDsnprintf(temp, (size_t)25, "3 end_trans %ld\n", trans_num); + + if ( H5C2_jb__write_to_buffer(struct_ptr, strlen(temp), temp) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__write_to_buffer() failed.\n") + } /* end if */ + + /* record the transaction number in the appropriate buffer index */ + if ( ( struct_ptr->cur_buf_free_space == struct_ptr->buf_size ) && + ( struct_ptr->put != 0 ) ) { + + (*struct_ptr->trans_on_disk_record)[struct_ptr->put - 1] = trans_num; + + } else if ( (struct_ptr->cur_buf_free_space == struct_ptr->buf_size ) && + (struct_ptr->put == 0 ) ) { + + (*struct_ptr->trans_on_disk_record)[struct_ptr->num_bufs-1] = trans_num; + + } else { + + (*struct_ptr->trans_on_disk_record)[struct_ptr->put] = trans_num; + } + + /* 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) + +} /* end H5C2_jb__end_transaction */ + + +/****************************************************************************** + * + * Function: H5C2_jb__comment + * + * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> + * Wednesday, February 6, 2008 + * + * 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__comment(H5C2_jbrb_t * struct_ptr, + char * comment_ptr) +{ + char * temp = NULL; + size_t temp_len; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5C2_jb__comment, FAIL) + + /* Check Arguments */ + HDassert(struct_ptr); + HDassert(comment_ptr); + HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); + + temp_len = strlen(comment_ptr) + 11; + if ( ( temp = H5MM_malloc(strlen(comment_ptr) + 11) ) == NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, \ + "allocation of temp buffer failed."); + } /* end if */ + + /* Write comment message */ + HDsnprintf(temp, temp_len, "C comment %s\n", comment_ptr); + + if ( H5C2_jb__write_to_buffer(struct_ptr, strlen(temp), temp) < 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_CANTJOURNAL, FAIL, \ + "H5C2_jb__write_to_buffer() failed.\n") + } /* end if */ + +done: + + if ( temp != NULL ) { + + temp = H5MM_xfree(temp); + if ( temp != NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "free of assembly buffer failed."); + } + } + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5C2_jb__comment */ + + +/****************************************************************************** + * + * 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. + * + ******************************************************************************/ + +herr_t +H5C2_jb__get_last_transaction_on_disk(H5C2_jbrb_t * struct_ptr, + unsigned long * trans_num_ptr) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5C2_jb__get_last_transaction_on_disk, FAIL) + + /* Check Arguments */ + HDassert( trans_num_ptr != 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 ) ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "bad struct_ptr.") + } + + * trans_num_ptr = struct_ptr->last_trans_on_disk; + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5C2_jb__get_last_transaction_on_disk */ + + +/****************************************************************************** + * + * Function: H5C2_jb__trunc + * + * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> + * Thursday, February 7, 2008 + * + * Purpose: Verify that there is no transaction in progress, and + * that the journal entry buffers are empty. Truncate + * the journal file, and reset the last transaction + * number to zero. Does not return until the file + * is truncated on disk. + * + * Returns: SUCCEED on success. + * + ******************************************************************************/ + +herr_t +H5C2_jb__trunc(H5C2_jbrb_t * struct_ptr) + +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5C2_jb__trunc, FAIL) + + /* 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, \ + "Attempt to truncate journal file while transaction in progress.") + } /* end if */ + + /* Verify that the journal buffers are empty */ + if ( struct_ptr->bufs_in_use != 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Attempt to truncate with non-empty buffers.") + } /* end if */ + + /* Truncate the journal file */ + if ( HDftruncate(struct_ptr->journal_file_fd, (off_t)0) < 0 ) { + + HGOTO_ERROR(H5E_IO, H5E_SYNCFAIL, FAIL, "Jounal file truncate failed.") + } /* end if */ + + /* Start back to top of journal buffer and journal file */ + struct_ptr->header_present = FALSE; + struct_ptr->journal_is_empty = TRUE; + + if ( HDlseek(struct_ptr->journal_file_fd, (off_t)0, SEEK_SET) == (off_t)-1 ) + { + HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "Jounal file seek failed.") + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5C2_jb__trunc */ + + +/****************************************************************************** + * + * Function: H5C2_jb__takedown + * + * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> + * Thursday, February 7, 2008 + * + * 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__takedown(H5C2_jbrb_t * struct_ptr) + +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5C2_jb__takedown, FAIL) + + /* Check Arguments */ + HDassert(struct_ptr); + HDassert(struct_ptr->magic == H5C2__H5C2_JBRB_T_MAGIC); + + /* Verify that the journal buffers are empty */ + if ( struct_ptr->bufs_in_use != 0 ) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Attempt to takedown with non-empty buffers.") + } /* end if */ + + /* Verify that the journal file has been truncated */ + if (struct_ptr->journal_is_empty != TRUE) { + + HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, \ + "Attempt to takedown with journal file not truncated.") + } /* end if */ + + /* Close and delete the journal file associated with struct_ptr */ + if ( HDclose(struct_ptr->journal_file_fd) < 0 ) { + + HGOTO_ERROR(H5E_IO, H5E_CLOSEERROR, FAIL, "Jounal file close failed.") + } /* end if */ + + if (remove(struct_ptr->jname) < 0) { + + HGOTO_ERROR(H5E_IO, H5E_REMOVEFAIL, FAIL, "Jounal file close failed.") + } /* end if */ + + /* Free all memory associated with struct_ptr */ + + if ( (*struct_ptr->buf)[0] != NULL ) { + + (*struct_ptr->buf)[0] = H5MM_xfree((*struct_ptr->buf)[0]); + if ( (*struct_ptr->buf)[0] != NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "free of buffers failed."); + } + } + + if ( struct_ptr->buf != NULL ) { + + struct_ptr->buf = H5MM_xfree(struct_ptr->buf); + if ( struct_ptr->buf != NULL ) { + + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, \ + "free of buffer pointer array failed."); + } + } + + /* JRM: Shouldn't you free struct_ptr->trans_on_disk_record?? */ + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5C2_jb__takedown */ + + +/****************************************************************************** + * + * Function: H5C2_jb__reconfigure + * + * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> + * Wednesday, February 6, 2008 + * + * Purpose: Re-configure the specified journal buffer ring buffer + * to use the supplied parameters. + * + * Returns: SUCCEED on success. + * + ******************************************************************************/ + +herr_t +H5C2_jb__reconfigure(H5C2_jbrb_t * struct_ptr, + size_t new_buf_size, + int new_num_bufs, + hbool_t new_use_aio) +{ +#if 0 /* body commented out pending implementation */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5C2_jb__reconfigure, FAIL) + + /* code */ + /* code */ + /* code */ + +done: + + FUNC_LEAVE_NOAPI(ret_value) +#else + return FAIL; +#endif +} /* end H5C2_jb__reconfigure */ + diff --git a/src/H5C2pkg.h b/src/H5C2pkg.h index 71c8e15..d29e4ad 100644 --- a/src/H5C2pkg.h +++ b/src/H5C2pkg.h @@ -43,6 +43,140 @@ /* Get needed headers */ #include "H5SLprivate.h" /* Skip lists */ + + /****************************************************************************** + * + * Structure: H5C2_jbrb_t + * + * Programmer: Mike McGreevy <mcgreevy@hdfgroup.org> + * Tuesday, February 5, 2008 + * + * Purpose: Instances of the H5C2_jbrb_t structure are used to + * implement a ring buffer of journal buffers. This + * structure is used in association with HDF5 File + * Recovery. It is used to journal metadata cache + * changes in an effort to be able to reproduce + * actions in the event of a crash during data writing. + * + * The fields of this structure are discussed below: + * + * + * 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. + * + * journal_file_fd: File Descriptor of the journal file that is being + * written to from this ring buffer. + * + * num_bufs: The number of journal buffers in the ring buffer. This + * must be at least 2 in the asynchronous case (one for + * storing journal entries as they are accumulated, and + * one for holding the last set of journal entries while + * they are being written to disk). + * + * buf_size: The size of each journal buffer in the ring buffer. This + * value is user specified, and will determine how much + * data each journal buffer can hold before a move to + * another journal buffer in the ring buffer is necessary. + * Typically, this will be a multiple of the block size of + * the underlying file system. + * + * bufs_in_use: This is the current number of dirty journal buffers + * in the ring buffer. + * + * jvers: The journal version number. This is used to keep track + * of the formatting changes of the journal file. + * + * get: Number of the journal buffer that is next in line to + * be written to disk. (i.e. the least recently dirtied + * journal buffer). + * + * put: Number of the journal buffer that is currently being + * written to. + * + * jentry_written: Boolean flag that indiciates if a journal entry has + * been written under the current transaction. + * + * use_aio: Boolean flag that indicates whether synchronous or + * asynchronous writes will be used. + * + * human_readable: Boolean flag that indicates whether the journal file + * is to be human readable or machine readable. + * + * journal_is_empty: Boolean flag that indicates if the journal file + * associated with the ring buffer is currently + * empty. + * + * cur_trans: Current transaction number, used to differentiate + * between differing journal entries in the journal file. + * + * last_trans_on_disk: Number of the last transaction that has successfully + * made it to disk. + * + * trans_in_prog: Boolean flag that indicates if a transaction is in + * progress or not. + * + * jname: Character array containing the name of the journal file. + * + * hdf5_file_name: Character array containing the name of the HDF5 file + * associated with this journal file. + * + * header_present: Boolean flag that indicates if the header message has + * been written into the current journal file or journal + * buffer. + * + * cur_buf_free_space: The amount of space remaining in the currently active + * journal buffer. This is used to determine when the + * ring buffer needs to switch to writing to the next + * journal buffer. + * + * rb_free_space: The amount of space remaining in the entire ring + * buffer. This is needed to determine if writes to + * the ring buffer need to loop around to the top of + * the chunk of allocated memory. + * + * head: A pointer to the location in the active journal buffer + * that is to be written to. + * + * buf: Array of char pointers to each journal buffer in the + * ring buffer. This is allocated as a single chunk of + * memory, and thus data can be written past a buffer + * boundary provided it will not extend past the end + * of the total area allocated for the ring buffer. + * + ******************************************************************************/ + +#define H5C2__H5C2_JBRB_T_MAGIC (unsigned)0x00D0A03 +#define H5C2__JOURNAL_VERSION 1 + +struct H5C2_jbrb_t +{ + uint32_t magic; + int journal_file_fd; + int num_bufs; + size_t buf_size; + int bufs_in_use; + unsigned long jvers; + int get; + int put; + hbool_t jentry_written; + hbool_t use_aio; + hbool_t human_readable; + hbool_t journal_is_empty; + unsigned long cur_trans; + unsigned long last_trans_on_disk; + hbool_t trans_in_prog; + char * jname; + char * hdf5_file_name; + hbool_t header_present; + size_t cur_buf_free_space; + size_t rb_free_space; + char * head; + unsigned long (*trans_on_disk_record)[]; + char *((*buf)[]); +}; + + /* With the introduction of the fractal heap, it is now possible for * entries to be dirtied, resized, and/or renamed in the flush callbacks. * As a result, on flushes, it may be necessary to make multiple passes diff --git a/src/H5C2private.h b/src/H5C2private.h index b70e968..a829ed5 100644 --- a/src/H5C2private.h +++ b/src/H5C2private.h @@ -1408,5 +1408,56 @@ H5_DLL herr_t H5C2_unprotect(H5C2_t * cache_ptr, H5_DLL herr_t H5C2_validate_resize_config(H5C2_auto_size_ctl_t * config_ptr, unsigned int tests); + +/*****************************************************************************/ +/****************** journal buffer function definitions: *********************/ +/*****************************************************************************/ + +typedef struct H5C2_jbrb_t H5C2_jbrb_t; + +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); + +H5_DLL herr_t H5C2_jb__init(H5C2_jbrb_t * struct_ptr, + char * HDF5_file_name, + char * journal_file_name, + size_t buf_size, + int num_bufs, + hbool_t use_aio, + hbool_t human_readable); + +H5_DLL herr_t H5C2_jb__start_transaction(H5C2_jbrb_t * struct_ptr, + unsigned long trans_num); + +H5_DLL herr_t H5C2_jb__journal_entry(H5C2_jbrb_t * struct_ptr, + unsigned long trans_num, + haddr_t base_addr, + size_t length, + char * body); + +H5_DLL herr_t H5C2_jb__end_transaction(H5C2_jbrb_t * struct_ptr, + unsigned long trans_num); + +H5_DLL herr_t H5C2_jb__comment(H5C2_jbrb_t * struct_ptr, + char * comment_ptr); + +H5_DLL herr_t H5C2_jb__get_last_transaction_on_disk(H5C2_jbrb_t * struct_ptr, + unsigned long * trans_num_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__reconfigure(H5C2_jbrb_t * struct_ptr, + size_t new_buf_size, + int new_num_bufs, + hbool_t new_use_aio); + + #endif /* !_H5C2private_H */ diff --git a/src/H5Edefin.h b/src/H5Edefin.h index 5638305..f63eee8 100644 --- a/src/H5Edefin.h +++ b/src/H5Edefin.h @@ -61,6 +61,9 @@ hid_t H5E_WRITEERROR_g = FAIL; /* Write failed */ hid_t H5E_CLOSEERROR_g = FAIL; /* Close failed */ hid_t H5E_OVERFLOW_g = FAIL; /* Address overflowed */ hid_t H5E_FCNTL_g = FAIL; /* File control (fcntl) failed */ +hid_t H5E_SYNCFAIL_g = FAIL; /* File sync failed */ +hid_t H5E_TRUNCFAIL_g = FAIL; /* File truncate failed */ +hid_t H5E_REMOVEFAIL_g = FAIL; /* File remove failed */ /* Resource errors */ hid_t H5E_NOSPACE_g = FAIL; /* No space available for allocation */ @@ -163,6 +166,7 @@ hid_t H5E_CANTMARKDIRTY_g = FAIL; /* Unable to mark a pinned entry as dirt hid_t H5E_CANTDIRTY_g = FAIL; /* Unable to mark metadata as dirty */ hid_t H5E_CANTEXPUNGE_g = FAIL; /* Unable to expunge a metadata cache entry */ hid_t H5E_CANTRESIZE_g = FAIL; /* Unable to resize a metadata cache entry */ +hid_t H5E_CANTJOURNAL_g = FAIL; /* Unable to write to journal file */ /* Link related errors */ hid_t H5E_TRAVERSE_g = FAIL; /* Link traversal failure */ diff --git a/src/H5Einit.h b/src/H5Einit.h index ac02d48..4d5704f 100644 --- a/src/H5Einit.h +++ b/src/H5Einit.h @@ -211,6 +211,21 @@ if((msg = H5E_create_msg(cls, H5E_MINOR, "File control (fcntl) failed"))==NULL) HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") if((H5E_FCNTL_g = H5I_register(H5I_ERROR_MSG, msg))<0) HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") +assert(H5E_SYNCFAIL_g==(-1)); +if((msg = H5E_create_msg(cls, H5E_MINOR, "File sync failed"))==NULL) + HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") +if((H5E_SYNCFAIL_g = H5I_register(H5I_ERROR_MSG, msg))<0) + HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") +assert(H5E_TRUNCFAIL_g==(-1)); +if((msg = H5E_create_msg(cls, H5E_MINOR, "File truncate failed"))==NULL) + HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") +if((H5E_TRUNCFAIL_g = H5I_register(H5I_ERROR_MSG, msg))<0) + HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") +assert(H5E_REMOVEFAIL_g==(-1)); +if((msg = H5E_create_msg(cls, H5E_MINOR, "File remove failed"))==NULL) + HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") +if((H5E_REMOVEFAIL_g = H5I_register(H5I_ERROR_MSG, msg))<0) + HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") /* Resource errors */ assert(H5E_NOSPACE_g==(-1)); @@ -617,6 +632,11 @@ if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to resize a metadata cache entr HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") if((H5E_CANTRESIZE_g = H5I_register(H5I_ERROR_MSG, msg))<0) HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") +assert(H5E_CANTJOURNAL_g==(-1)); +if((msg = H5E_create_msg(cls, H5E_MINOR, "Unable to write to journal file"))==NULL) + HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, "error message initialization failed") +if((H5E_CANTJOURNAL_g = H5I_register(H5I_ERROR_MSG, msg))<0) + HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error message") /* Link related errors */ assert(H5E_TRAVERSE_g==(-1)); diff --git a/src/H5Epubgen.h b/src/H5Epubgen.h index 8386e0f..51a5d16 100644 --- a/src/H5Epubgen.h +++ b/src/H5Epubgen.h @@ -96,12 +96,18 @@ H5_DLLVAR hid_t H5E_CACHE_g; /* Object cache */ #define H5E_CLOSEERROR (H5OPEN H5E_CLOSEERROR_g) #define H5E_OVERFLOW (H5OPEN H5E_OVERFLOW_g) #define H5E_FCNTL (H5OPEN H5E_FCNTL_g) +#define H5E_SYNCFAIL (H5OPEN H5E_SYNCFAIL_g) +#define H5E_TRUNCFAIL (H5OPEN H5E_TRUNCFAIL_g) +#define H5E_REMOVEFAIL (H5OPEN H5E_REMOVEFAIL_g) H5_DLLVAR hid_t H5E_SEEKERROR_g; /* Seek failed */ H5_DLLVAR hid_t H5E_READERROR_g; /* Read failed */ H5_DLLVAR hid_t H5E_WRITEERROR_g; /* Write failed */ H5_DLLVAR hid_t H5E_CLOSEERROR_g; /* Close failed */ H5_DLLVAR hid_t H5E_OVERFLOW_g; /* Address overflowed */ H5_DLLVAR hid_t H5E_FCNTL_g; /* File control (fcntl) failed */ +H5_DLLVAR hid_t H5E_SYNCFAIL_g; /* File sync failed */ +H5_DLLVAR hid_t H5E_TRUNCFAIL_g; /* File truncate failed */ +H5_DLLVAR hid_t H5E_REMOVEFAIL_g; /* File remove failed */ /* Resource errors */ #define H5E_NOSPACE (H5OPEN H5E_NOSPACE_g) @@ -264,6 +270,7 @@ H5_DLLVAR hid_t H5E_NOIDS_g; /* Out of IDs for group */ #define H5E_CANTDIRTY (H5OPEN H5E_CANTDIRTY_g) #define H5E_CANTEXPUNGE (H5OPEN H5E_CANTEXPUNGE_g) #define H5E_CANTRESIZE (H5OPEN H5E_CANTRESIZE_g) +#define H5E_CANTJOURNAL (H5OPEN H5E_CANTJOURNAL_g) H5_DLLVAR hid_t H5E_CANTFLUSH_g; /* Unable to flush data from cache */ H5_DLLVAR hid_t H5E_CANTSERIALIZE_g; /* Unable to serialize data from cache */ H5_DLLVAR hid_t H5E_CANTLOAD_g; /* Unable to load metadata into cache */ @@ -280,6 +287,7 @@ H5_DLLVAR hid_t H5E_CANTMARKDIRTY_g; /* Unable to mark a pinned entry as dirty * H5_DLLVAR hid_t H5E_CANTDIRTY_g; /* Unable to mark metadata as dirty */ H5_DLLVAR hid_t H5E_CANTEXPUNGE_g; /* Unable to expunge a metadata cache entry */ H5_DLLVAR hid_t H5E_CANTRESIZE_g; /* Unable to resize a metadata cache entry */ +H5_DLLVAR hid_t H5E_CANTJOURNAL_g; /* Unable to write to journal file */ /* Link related errors */ #define H5E_TRAVERSE (H5OPEN H5E_TRAVERSE_g) diff --git a/src/H5Eterm.h b/src/H5Eterm.h index dedc313..bc4e8a7 100644 --- a/src/H5Eterm.h +++ b/src/H5Eterm.h @@ -62,7 +62,10 @@ H5E_READERROR_g= H5E_WRITEERROR_g= H5E_CLOSEERROR_g= H5E_OVERFLOW_g= -H5E_FCNTL_g= +H5E_FCNTL_g= +H5E_SYNCFAIL_g= +H5E_TRUNCFAIL_g= +H5E_REMOVEFAIL_g= /* Resource errors */ H5E_NOSPACE_g= @@ -164,7 +167,8 @@ H5E_CANTUNPIN_g= H5E_CANTMARKDIRTY_g= H5E_CANTDIRTY_g= H5E_CANTEXPUNGE_g= -H5E_CANTRESIZE_g= +H5E_CANTRESIZE_g= +H5E_CANTJOURNAL_g= /* Link related errors */ H5E_TRAVERSE_g= diff --git a/src/H5err.txt b/src/H5err.txt index 844bd57..abc2eac 100644 --- a/src/H5err.txt +++ b/src/H5err.txt @@ -137,6 +137,9 @@ MINOR, FILE, H5E_WRITEERROR, Write failed MINOR, FILE, H5E_CLOSEERROR, Close failed MINOR, FILE, H5E_OVERFLOW, Address overflowed MINOR, FILE, H5E_FCNTL, File control (fcntl) failed +MINOR, FILE, H5E_SYNCFAIL, File sync failed +MINOR, FILE, H5E_TRUNCFAIL, File truncate failed +MINOR, FILE, H5E_REMOVEFAIL, File remove failed # Function entry/exit interface errors MINOR, FUNC, H5E_CANTINIT, Unable to initialize object @@ -168,6 +171,8 @@ MINOR, CACHE, H5E_CANTMARKDIRTY, Unable to mark a pinned entry as dirty MINOR, CACHE, H5E_CANTDIRTY, Unable to mark metadata as dirty MINOR, CACHE, H5E_CANTEXPUNGE, Unable to expunge a metadata cache entry MINOR, CACHE, H5E_CANTRESIZE, Unable to resize a metadata cache entry +MINOR, CACHE, H5E_CANTJOURNAL, Unable to write to journal file + # B-tree related errors MINOR, BTREE, H5E_NOTFOUND, Object not found diff --git a/test/Makefile.am b/test/Makefile.am index 84149cb..9219d80 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -37,7 +37,7 @@ SCRIPT_DEPEND = error_test$(EXEEXT) err_compat$(EXEEXT) # the library yet. Move them to the end so that their failure do not block # other current library code tests. TEST_PROG=testhdf5 lheap ohdr stab gheap cache cache_api cache2 cache2_api \ - pool hyperslab istore bittests dt_arith \ + cache2_journal pool hyperslab istore bittests dt_arith \ dtypes dsets cmpd_dset extend external objcopy links unlink big mtime \ fillval mount flush1 flush2 enum \ set_extent ttsafe \ diff --git a/test/Makefile.in b/test/Makefile.in index c81102b..cf0ed18 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -72,16 +72,17 @@ am_libh5test_la_OBJECTS = h5test.lo testframe.lo cache_common.lo \ libh5test_la_OBJECTS = $(am_libh5test_la_OBJECTS) am__EXEEXT_1 = testhdf5$(EXEEXT) lheap$(EXEEXT) ohdr$(EXEEXT) \ stab$(EXEEXT) gheap$(EXEEXT) cache$(EXEEXT) cache_api$(EXEEXT) \ - cache2$(EXEEXT) cache2_api$(EXEEXT) pool$(EXEEXT) \ - hyperslab$(EXEEXT) istore$(EXEEXT) bittests$(EXEEXT) \ - dt_arith$(EXEEXT) dtypes$(EXEEXT) dsets$(EXEEXT) \ - cmpd_dset$(EXEEXT) extend$(EXEEXT) external$(EXEEXT) \ - objcopy$(EXEEXT) links$(EXEEXT) unlink$(EXEEXT) big$(EXEEXT) \ - mtime$(EXEEXT) fillval$(EXEEXT) mount$(EXEEXT) flush1$(EXEEXT) \ - flush2$(EXEEXT) enum$(EXEEXT) set_extent$(EXEEXT) \ - ttsafe$(EXEEXT) getname$(EXEEXT) vfd$(EXEEXT) ntypes$(EXEEXT) \ - dangle$(EXEEXT) dtransform$(EXEEXT) reserved$(EXEEXT) \ - cross_read$(EXEEXT) btree2$(EXEEXT) fheap$(EXEEXT) + cache2$(EXEEXT) cache2_api$(EXEEXT) cache2_journal$(EXEEXT) \ + pool$(EXEEXT) hyperslab$(EXEEXT) istore$(EXEEXT) \ + bittests$(EXEEXT) dt_arith$(EXEEXT) dtypes$(EXEEXT) \ + dsets$(EXEEXT) cmpd_dset$(EXEEXT) extend$(EXEEXT) \ + external$(EXEEXT) objcopy$(EXEEXT) links$(EXEEXT) \ + unlink$(EXEEXT) big$(EXEEXT) mtime$(EXEEXT) fillval$(EXEEXT) \ + mount$(EXEEXT) flush1$(EXEEXT) flush2$(EXEEXT) enum$(EXEEXT) \ + set_extent$(EXEEXT) ttsafe$(EXEEXT) getname$(EXEEXT) \ + vfd$(EXEEXT) ntypes$(EXEEXT) dangle$(EXEEXT) \ + dtransform$(EXEEXT) reserved$(EXEEXT) cross_read$(EXEEXT) \ + btree2$(EXEEXT) fheap$(EXEEXT) am__EXEEXT_2 = gen_bogus$(EXEEXT) gen_cross$(EXEEXT) \ gen_deflate$(EXEEXT) gen_filters$(EXEEXT) \ gen_new_array$(EXEEXT) gen_new_fill$(EXEEXT) \ @@ -114,6 +115,10 @@ cache2_api_SOURCES = cache2_api.c cache2_api_OBJECTS = cache2_api.$(OBJEXT) cache2_api_LDADD = $(LDADD) cache2_api_DEPENDENCIES = libh5test.la $(LIBHDF5) +cache2_journal_SOURCES = cache2_journal.c +cache2_journal_OBJECTS = cache2_journal.$(OBJEXT) +cache2_journal_LDADD = $(LDADD) +cache2_journal_DEPENDENCIES = libh5test.la $(LIBHDF5) cache_api_SOURCES = cache_api.c cache_api_OBJECTS = cache_api.$(OBJEXT) cache_api_LDADD = $(LDADD) @@ -337,19 +342,7 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libh5test_la_SOURCES) big.c bittests.c btree2.c cache.c \ - cache2.c cache2_api.c cache_api.c cmpd_dset.c cross_read.c \ - dangle.c dsets.c dt_arith.c dtransform.c dtypes.c enum.c \ - err_compat.c error_test.c extend.c external.c fheap.c \ - fillval.c flush1.c flush2.c gen_bogus.c gen_cross.c \ - gen_deflate.c gen_filters.c gen_new_array.c gen_new_fill.c \ - gen_new_group.c gen_new_mtime.c gen_new_super.c \ - gen_noencoder.c gen_nullspace.c gen_udlinks.c getname.c \ - gheap.c hyperslab.c istore.c lheap.c links.c mount.c mtime.c \ - ntypes.c objcopy.c ohdr.c pool.c reserved.c set_extent.c \ - space_overflow.c stab.c $(testhdf5_SOURCES) testmeta.c \ - $(ttsafe_SOURCES) unlink.c vfd.c -DIST_SOURCES = $(libh5test_la_SOURCES) big.c bittests.c btree2.c \ - cache.c cache2.c cache2_api.c cache_api.c cmpd_dset.c \ + cache2.c cache2_api.c cache2_journal.c cache_api.c cmpd_dset.c \ cross_read.c dangle.c dsets.c dt_arith.c dtransform.c dtypes.c \ enum.c err_compat.c error_test.c extend.c external.c fheap.c \ fillval.c flush1.c flush2.c gen_bogus.c gen_cross.c \ @@ -360,6 +353,18 @@ DIST_SOURCES = $(libh5test_la_SOURCES) big.c bittests.c btree2.c \ ntypes.c objcopy.c ohdr.c pool.c reserved.c set_extent.c \ space_overflow.c stab.c $(testhdf5_SOURCES) testmeta.c \ $(ttsafe_SOURCES) unlink.c vfd.c +DIST_SOURCES = $(libh5test_la_SOURCES) big.c bittests.c btree2.c \ + cache.c cache2.c cache2_api.c cache2_journal.c cache_api.c \ + cmpd_dset.c cross_read.c dangle.c dsets.c dt_arith.c \ + dtransform.c dtypes.c enum.c err_compat.c error_test.c \ + extend.c external.c fheap.c fillval.c flush1.c flush2.c \ + gen_bogus.c gen_cross.c gen_deflate.c gen_filters.c \ + gen_new_array.c gen_new_fill.c gen_new_group.c gen_new_mtime.c \ + gen_new_super.c gen_noencoder.c gen_nullspace.c gen_udlinks.c \ + getname.c gheap.c hyperslab.c istore.c lheap.c links.c mount.c \ + mtime.c ntypes.c objcopy.c ohdr.c pool.c reserved.c \ + set_extent.c space_overflow.c stab.c $(testhdf5_SOURCES) \ + testmeta.c $(ttsafe_SOURCES) unlink.c vfd.c ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -627,7 +632,7 @@ SCRIPT_DEPEND = error_test$(EXEEXT) err_compat$(EXEEXT) # the library yet. Move them to the end so that their failure do not block # other current library code tests. TEST_PROG = testhdf5 lheap ohdr stab gheap cache cache_api cache2 cache2_api \ - pool hyperslab istore bittests dt_arith \ + cache2_journal pool hyperslab istore bittests dt_arith \ dtypes dsets cmpd_dset extend external objcopy links unlink big mtime \ fillval mount flush1 flush2 enum \ set_extent ttsafe \ @@ -764,6 +769,9 @@ cache2$(EXEEXT): $(cache2_OBJECTS) $(cache2_DEPENDENCIES) cache2_api$(EXEEXT): $(cache2_api_OBJECTS) $(cache2_api_DEPENDENCIES) @rm -f cache2_api$(EXEEXT) $(LINK) $(cache2_api_OBJECTS) $(cache2_api_LDADD) $(LIBS) +cache2_journal$(EXEEXT): $(cache2_journal_OBJECTS) $(cache2_journal_DEPENDENCIES) + @rm -f cache2_journal$(EXEEXT) + $(LINK) $(cache2_journal_OBJECTS) $(cache2_journal_LDADD) $(LIBS) cache_api$(EXEEXT): $(cache_api_OBJECTS) $(cache_api_DEPENDENCIES) @rm -f cache_api$(EXEEXT) $(LINK) $(cache_api_OBJECTS) $(cache_api_LDADD) $(LIBS) @@ -928,6 +936,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache2_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache2_common.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache2_journal.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache_common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmpd_dset.Po@am__quote@ diff --git a/test/cache2_journal.c b/test/cache2_journal.c new file mode 100644 index 0000000..39682e1 --- /dev/null +++ b/test/cache2_journal.c @@ -0,0 +1,426 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* Programmer: John Mainzer + * 11/10/05 + * + * This file contains tests for the metadata journaling + * features implemented in H5C2.c and friends. + */ + +#include "h5test.h" +#include "H5Iprivate.h" +#include "H5AC2private.h" +#include "cache2_common.h" + +#define HDF5_FILE_NAME "HDF5.file" + +/* global variable declarations: */ + +const char *FILENAMES[] = { + "cache_test", + "cache_journal_test", + NULL +}; + + +/* private function declarations: */ + +static void check_buffer_writes(void); + +static void write_flush_verify(H5C2_jbrb_t * struct_ptr, + int size, + char * data, + FILE * readback); + +static void write_noflush_verify(H5C2_jbrb_t * struct_ptr, + int size, + char * data, + FILE * readback, + int repeats); + + +/**************************************************************************/ +/**************************************************************************/ +/********************************* tests: *********************************/ +/**************************************************************************/ +/**************************************************************************/ + +/* JRM -- header comment?? */ + +static void +check_buffer_writes(void) +{ + const char * fcn_name = "check_buffer_writes(): "; + char filename[512]; + int i; + herr_t result; + H5C2_jbrb_t * struct_ptr; + FILE * readback; + hbool_t show_progress = FALSE; + int32_t checkpoint = 1; + char filldata[13][100]; + + TESTING("metadata buffer & file writes"); + + pass2 = TRUE; + + /* Initialize data to get written as tests */ + memcpy(filldata[0], "3456789\n", 9); + memcpy(filldata[1], "abcdefghijklmn\n", 16); + memcpy(filldata[2], "ABCDEFGHIJKLMNO\n", 17); + memcpy(filldata[3], "AaBbCcDdEeFfGgHh\n", 18); + memcpy(filldata[4], "ZAB-ZAB-ZAB-ZAB-ZAB-ZAB-ZAB-ZA\n", 32); + memcpy(filldata[5], "ABC-ABC-ABC-ABC-ABC-ABC-ABC-ABC\n", 33); + memcpy(filldata[6], "BCD-BCD-BCD-BCD-BCD-BCD-BCD-BCD-\n", 34); + memcpy(filldata[7], "12345-12345-12345-12345-12345-12345-12345-1234\n", 48); + memcpy(filldata[8], "01234-01234-01234-01234-01234-01234-01234-01234\n", 49); + memcpy(filldata[9], "23456-23456-23456-23456-23456-23456-23456-23456-\n", 50); + memcpy(filldata[10], "aaaa-bbbb-cccc-dddd-eeee-ffff-gggg-hhhh-iiii-jjjj-kkkk-llll-mmmm-nnnn-oooo-pppp-qqqq-rrrr-ssss\n", 96); + memcpy(filldata[11], "bbbb-cccc-dddd-eeee-ffff-gggg-hhhh-iiii-jjjj-kkkk-llll-mmmm-nnnn-oooo-pppp-qqqq-rrrr-ssss-tttt-\n", 97); + memcpy(filldata[12], "cccc-dddd-eeee-ffff-gggg-hhhh-iiii-jjjj-kkkk-llll-mmmm-nnnn-oooo-pppp-qqqq-rrrr-ssss-tttt-uuuu-v\n", 98); + + /* Assert that size of data is as expected */ + HDassert(strlen(filldata[0]) == 8); + HDassert(strlen(filldata[1]) == 15); + HDassert(strlen(filldata[2]) == 16); + HDassert(strlen(filldata[3]) == 17); + HDassert(strlen(filldata[4]) == 31); + HDassert(strlen(filldata[5]) == 32); + HDassert(strlen(filldata[6]) == 33); + HDassert(strlen(filldata[7]) == 47); + HDassert(strlen(filldata[8]) == 48); + HDassert(strlen(filldata[9]) == 49); + HDassert(strlen(filldata[10]) == 95); + HDassert(strlen(filldata[11]) == 96); + HDassert(strlen(filldata[12]) == 97); + + /* Allocate memory for H5C2_jbrb_t structure */ + /* JRM: why allocate this? Why not just declare it as a local + * variable? + */ + if ( pass2 ) { + + if (NULL == (struct_ptr = malloc(sizeof(H5C2_jbrb_t)))) { + + pass2 = FALSE; + failure_mssg2 = + "Can't allocate memory for H5C2_jbrb_t structure.\n"; + } + struct_ptr->magic = H5C2__H5C2_JBRB_T_MAGIC; + } + + if ( show_progress ) /* 1 */ + HDfprintf(stdout, "%s%0d -- pass = %d\n", fcn_name, + checkpoint++, (int)pass2); + + /* setup the file name */ + if ( pass2 ) { + + if ( h5_fixname(FILENAMES[1], H5P_DEFAULT, filename, sizeof(filename)) + == NULL ) { + + pass2 = FALSE; + failure_mssg2 = "h5_fixname() failed.\n"; + } + } + + if ( show_progress ) /* 2 */ + HDfprintf(stdout, "%s%0d -- pass = %d\n", fcn_name, + checkpoint++, (int)pass2); + + /* Initialize H5C2_jbrb_t structure. */ + if ( pass2 ) { + + result = H5C2_jb__init(/* H5C2_jbrb_t */ struct_ptr, + /* HDF5 file name */ HDF5_FILE_NAME, + /* journal file name */ filename, + /* Buffer size */ 16, + /* Number of Buffers */ 3, + /* Use Synchronois I/O */ FALSE, + /* human readable journal */ TRUE); + + if ( result != 0) { + + pass2 = FALSE; + failure_mssg2 = "H5C2_jb_init failed.\n"; + } + } + + if ( show_progress ) /* 3 */ + HDfprintf(stdout, "%s%0d -- pass = %d\n", fcn_name, + checkpoint++, (int)pass2); + + /* Flush out buffers to disk */ + if ( pass2 ) { + + if ( H5C2_jb__flush(struct_ptr) != SUCCEED ) { + + pass2 = FALSE; + failure_mssg2 = "H5C2_jb_flush failed.\n"; + } + } + + /* Truncate journal file */ + if ( pass2 ) { + + if ( H5C2_jb__trunc(struct_ptr) != SUCCEED ) { + + pass2 = FALSE; + failure_mssg2 = "H5C2_jb_trunc failed.\n"; + } + } + + if ( show_progress ) /* 4 */ + HDfprintf(stdout, "%s%0d -- pass = %d\n", fcn_name, + checkpoint++, (int)pass2); + + /* open journal file for reading */ + readback = fopen(filename, "r"); + + + /* run a collection of calls to write_flush_verify(). These calls + * write specific lengths of data into the journal buffers and + * then flushes them to disk, and ensures that what makes it to + * disk is as expected + */ + + for (i=1; i<13; i++) { + + write_flush_verify(struct_ptr, + (int)strlen(filldata[i]), + filldata[i], + readback); + + if ( show_progress ) + HDfprintf(stdout, "%s%0d -- pass = %d\n", fcn_name, + checkpoint++, (int)pass2); + + } + + /* run a collection of calls to write_noflush_verify(). These + * calls write specific lengths of data into the journal buffers + * multiple times, but only flushes at the end of the set of writes. + * This tests to ensure that the automatic flush calls in + * H5C2_jb__write_to_buffer are working properly. The routine then + * ensures that what makes it it disk is as expected + */ + + write_noflush_verify(struct_ptr, 15, filldata[1], readback, 16); + + if ( show_progress ) /* 17 */ + HDfprintf(stdout, "%s%0d -- pass = %d\n", fcn_name, + checkpoint++, (int)pass2); + + write_noflush_verify(struct_ptr, 16, filldata[2], readback, 6); + + if ( show_progress ) /* 18 */ + HDfprintf(stdout, "%s%0d -- pass = %d\n", fcn_name, + checkpoint++, (int)pass2); + + write_noflush_verify(struct_ptr, 17, filldata[3], readback, 16); + + if ( show_progress ) /* 19 */ + HDfprintf(stdout, "%s%0d -- pass = %d\n", fcn_name, + checkpoint++, (int)pass2); + + write_noflush_verify(struct_ptr, 47, filldata[7], readback, 16); + + if ( show_progress ) /* 20 */ + HDfprintf(stdout, "%s%0d -- pass = %d\n", fcn_name, + checkpoint++, (int)pass2); + + write_noflush_verify(struct_ptr, 48, filldata[8], readback, 6); + + if ( show_progress ) /* 21 */ + HDfprintf(stdout, "%s%0d -- pass = %d\n", fcn_name, + checkpoint++, (int)pass2); + + write_noflush_verify(struct_ptr, 49, filldata[9], readback, 16); + + if ( show_progress ) /* 22 */ + HDfprintf(stdout, "%s%0d -- pass = %d\n", fcn_name, + checkpoint++, (int)pass2); + + /* close the journal file's file pointer, and truncate the journal file */ + /* JRM -- Don't you want to close the readback file + * if it is open, not just if there is a pass? + */ + if ( pass2 ) { + + fclose(readback); + + if ( H5C2_jb__trunc(struct_ptr) != SUCCEED ) { + + pass2 = FALSE; + failure_mssg2 = "H5C2_jb__trunc failed.\n"; + } + } + + /* take down the journal file */ + if ( pass2 ) { + + if (H5C2_jb__takedown(struct_ptr) != SUCCEED) { + + pass2 = FALSE; + failure_mssg2 = "H5C2_jb__takedown failed.\n"; + } + + free(struct_ptr); + } + + /* report pass / failure information */ + if ( pass2 ) { PASSED(); } else { H5_FAILED(); } + + if ( ! pass2 ) + HDfprintf(stdout, "%s: failure_mssg2 = \"%s\".\n", + fcn_name, failure_mssg2); + + return; + +} /* check_buffer_writes */ + + +/* JRM: header comment? */ + + +static void +write_flush_verify(H5C2_jbrb_t * struct_ptr, + int size, + char * data, + FILE * readback) +{ + char verify[150]; + + if ( pass2 ) { + + if ( H5C2_jb__write_to_buffer(struct_ptr, size, data) != SUCCEED ) { + + pass2 = FALSE; + failure_mssg2 = "H5C2_jb__write_to_buffer failed.\n"; + } + } + + if ( pass2 ) { + + if ( H5C2_jb__flush(struct_ptr) != SUCCEED ) { + + pass2 = FALSE; + failure_mssg2 = "H5C2_jb_flush failed.\n"; + } + } + + if ( pass2 ) { + + fgets(verify, size+10, readback); + + if (strcmp(verify, data) != 0) { + + pass2 = FALSE; + failure_mssg2 = "Journal entry not written correctly.\n"; + printf("message read from file : %s\n", verify); + printf("message supplied : %s\n", data); + } + } + + return; + +} /* write_flush_verify */ + + +/* JRM: header comment? */ + + +static void +write_noflush_verify(H5C2_jbrb_t * struct_ptr, + int size, + char * data, + FILE * readback, + int repeats) +{ + int i; + char verify[150]; + + for (i=0; i<repeats; i++) { + + if ( pass2 ) { + + if ( H5C2_jb__write_to_buffer(struct_ptr, size, data) != SUCCEED ) { + + pass2 = FALSE; + failure_mssg2 = "H5C2_jb__write_to_buffer failed.\n"; + } /* end if */ + } /* end if */ + } /* end for */ + + if ( pass2 ) { + + if ( H5C2_jb__flush(struct_ptr) != SUCCEED ) { + + pass2 = FALSE; + failure_mssg2 = "H5C2_jb_flush failed.\n"; + } + } + + for (i=0; i<repeats; i++) { + + if ( pass2 ) { + fgets(verify, size+10, readback); + if (strcmp(verify, data) != 0) { + + pass2 = FALSE; + failure_mssg2 = "Journal entry not written correctly.\n"; + printf("message read from file : %s\n", verify); + printf("message supplied : %s\n", data); + } /* end if */ + } /* end if */ + } /* end for */ + + return; + +} /* write_noflush_verify */ + + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: Run tests on the cache code contained in H5C2.c + * + * Return: Success: + * + * Failure: + * + * Programmer: John Mainzer + * 6/24/04 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +int +main(void) +{ + int express_test; + + H5open(); + + express_test = GetTestExpress(); + + check_buffer_writes(); + + return(0); + +} /* main() */ |