summaryrefslogtreecommitdiffstats
path: root/src/H5C2journal.c
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 /src/H5C2journal.c
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.
Diffstat (limited to 'src/H5C2journal.c')
-rw-r--r--src/H5C2journal.c1180
1 files changed, 1179 insertions, 1 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 */
+