3.2. Two journaled files and an application crash

A simple way to simulate an application crash is forcing a division by zero exception: this may not be the cause of the crash of your application once it has been moved to production environment, but it's an example can light on libjf power.

Example 3-2. two_files_crash.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_journal_commit(&j);
    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 program ended OK!\n");
    85	        return 0;
    86	}
      

two_files_crash.c is slightly different than two_files.c:

Row 47

a first commit is performed by our application to successfully close the first transaction

Rows 64-68

a trick has been introduced to force a "division by zero" exception (row 67) avoiding the situation is detected by most compilers.

To compile two_files_crash.c source code use our old friend libtool command:

libtool --mode=link gcc -Wall -I/opt/libjf/include -L/opt/libjf/lib -ljf \
        -o two_files_crash two_files_crash.c
    
if you executed two_files program too, the execution of two_files_crash should exploit an error condition:
tiian@linux:~/tutorial> ./two_files_crash
-15/ERROR: file can not be created because it already exists
    
the problem is due to two_files_crash request of "new journal creation" (take a look at row 16); remove old files and run it again:
tiian@linux:~/tutorial> rm jf_tut_foo-*
tiian@linux:~/tutorial> ./two_files_crash
Floating point exception
    
our application crashed as expected, look at journaled files:
tiian@linux:~/tutorial> ls -la jf_tut_foo-*
-rw-r--r--  1 tiian users    28 2005-08-11 17:34 jf_tut_foo-data1
-rw-r--r--  1 tiian users    29 2005-08-11 17:34 jf_tut_foo-data2
-rw-r--r--  1 tiian users 16605 2005-08-11 17:34 jf_tut_foo-journal
tiian@linux:~/tutorial> cat jf_tut_foo-data1
First string for first file
tiian@linux:~/tutorial> cat jf_tut_foo-data2
First string for second file
    
strings of first transaction are at their place as desired, strings of second transaction were backed out as expected and data kept by journaled files are consistent.

You may enjoy transactionality of this example moving rows 64-68 in different places like between rows 40 and 41.