When you are working with two or more journaled files, sometimes you need to close a "partial transaction" before the global transaction has completed: this happens when you want to save the fact you tried the transaction and a rollback would erase this information. The following example will show this behavior.
Example 3-3. two_files_crash2.c
1 #include <jf_file.h> 2 int main() 3 { 4 int rc; 5 size_t write; 6 jf_journal_t j; 7 jf_file_t jf1, jf2; 8 struct jf_journal_opts_s jopts; 9 struct jf_file_open_opts_s fopts; 10 const char *file1_data1 = "First string for first file\n"; 11 const char *file1_data2 = "Second string for first file\n"; 12 const char *file2_data1 = "First string for second file\n"; 13 const char *file2_data2 = "Second string for second file\n"; 14 int x, y; 15 jf_set_default_journal_opts(&jopts); 16 jopts.flags |= JF_JOURNAL_PROP_OPEN_O_CREAT | 17 JF_JOURNAL_PROP_OPEN_O_EXCL; 18 rc = jf_journal_open(&j, "jf_tut_foo-journal", 2, &jopts); 19 if (JF_RC_OK != rc) { 20 printf("%d/%s\n", rc, jf_strerror(rc)); 21 return 1; 22 } 23 jf_set_default_file_open_opts(&fopts); 24 fopts.join_the_journal = TRUE; 25 rc = jf_file_open(&jf1, &j, "jf_tut_foo-data1", "w", &fopts); 26 if (JF_RC_OK != rc) { 27 printf("%d/%s\n", rc, jf_strerror(rc)); 28 return 1; 29 } 30 rc = jf_file_open(&jf2, &j, "jf_tut_foo-data2", "w", &fopts); 31 if (JF_RC_OK != rc) { 32 printf("%d/%s\n", rc, jf_strerror(rc)); 33 return 1; 34 } 35 rc = jf_file_write(&jf1, file1_data1, strlen(file1_data1), 36 &write); 37 if (JF_RC_OK != rc) { 38 printf("%d/%s\n", rc, jf_strerror(rc)); 39 return 1; 40 } 41 rc = jf_file_write(&jf2, file2_data1, strlen(file2_data1), 42 &write); 43 if (JF_RC_OK != rc) { 44 printf("%d/%s\n", rc, jf_strerror(rc)); 45 return 1; 46 } 47 rc = jf_file_commit(&jf2); 48 if (JF_RC_OK != rc) { 49 printf("%d/%s\n", rc, jf_strerror(rc)); 50 return 1; 51 } 52 rc = jf_file_write(&jf1, file1_data2, strlen(file1_data2), 53 &write); 54 if (JF_RC_OK != rc) { 55 printf("%d/%s\n", rc, jf_strerror(rc)); 56 return 1; 57 } 58 rc = jf_file_write(&jf2, file2_data2, strlen(file2_data2), 59 &write); 60 if (JF_RC_OK != rc) { 61 printf("%d/%s\n", rc, jf_strerror(rc)); 62 return 1; 63 } 64 /* a fool crash simulation */ 65 x = 0; y = 5; 66 while (TRUE) 67 x += 5 / y--; 68 printf("This should not print x = %d\n", x); 69 rc = jf_file_close(&jf1); 70 if (JF_RC_OK != rc) { 71 printf("%d/%s\n", rc, jf_strerror(rc)); 72 return 1; 73 } 74 rc = jf_file_close(&jf2); 75 if (JF_RC_OK != rc) { 76 printf("%d/%s\n", rc, jf_strerror(rc)); 77 return 1; 78 } 79 rc = jf_journal_close(&j); 80 if (JF_RC_OK != rc) { 81 printf("%d/%s\n", rc, jf_strerror(rc)); 82 return 1; 83 } 84 printf("two_files_crash II program ended OK!\n"); 85 return 0; 86 }
At row 47, we changed
jf_journal_commit(&j)
with
jf_file_commit(&jf2)
: instead
of committing
the whole "unit of work", we decided to commit only the
changes operated against jf2.
The source two_files_crash2.c can be compiled with this command:
libtool --mode=link gcc -Wall -I/opt/libjf/include -L/opt/libjf/lib -ljf \ -o two_files_crash2 two_files_crash2.cexecute it after you have deleted journal and journaled files created by two_files_crash:
tiian@linux:~/tutorial> rm jf_tut_foo-* tiian@linux:~/tutorial> ./two_files_crash2 Floating point exceptiontake a look to files produced by two_files_crash2:
tiian@linux:~/tutorial> ls -la jf_tut_foo-* -rw-r--r-- 1 tiian users 0 2005-08-12 22:37 jf_tut_foo-data1 -rw-r--r-- 1 tiian users 29 2005-08-12 22:37 jf_tut_foo-data2 -rw-r--r-- 1 tiian users 16561 2005-08-12 22:37 jf_tut_foo-journal tiian@linux:~/tutorial> cat jf_tut_foo-data2 First string for second filefirst journaled file is empty because no data has been committed to it, second journaled file contains the first string because a partial commit has been performed.
Can libjf commit/rollback a random set of journaled files? At the time of this writing, libjf can commit/rollback only:
all the journaled files associated to a journal
a specific journaled file