summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Mainzer <mainzer@hdfgroup.org>2008-02-25 10:01:56 (GMT)
committerJohn Mainzer <mainzer@hdfgroup.org>2008-02-25 10:01:56 (GMT)
commit738078322dd2b189ec1233c9ea59f218c2008740 (patch)
tree81ac2180a5f6eed1d65198de2abf2c6569bf48bb
parentcd571e4a45e5af71ae608388141e6b28a16f8171 (diff)
downloadhdf5-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.c1180
-rw-r--r--src/H5C2pkg.h134
-rw-r--r--src/H5C2private.h51
-rw-r--r--src/H5Edefin.h4
-rw-r--r--src/H5Einit.h20
-rw-r--r--src/H5Epubgen.h8
-rw-r--r--src/H5Eterm.h8
-rw-r--r--src/H5err.txt5
-rw-r--r--test/Makefile.am2
-rw-r--r--test/Makefile.in57
-rw-r--r--test/cache2_journal.c426
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() */