State-reconstruction example

In the following example, in addition to reopening the connection to the server, the client also reconstructs the state of the connection by seeking to the current file (connection) offset.

This example also shows how the client can maintain state information that can be used by the recovery functions to return to a previously check-pointed state before the failure, so that the message transmission can continue properly.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <ha/cover.h>

#define REMOTEFILE "/path/to/remote/file"

typedef struct handle {
    int nr;
    int curr_offset;
} Handle ;

int recover_conn(int oldfd, void *hdl)
{
    int newfd;
    int newfd2;
    Handle *thdl;
    thdl = (Handle *)hdl;
    printf("recovering for fd %d inside function\n",oldfd);
   /* re-open the file */
    newfd = ha_reopen(oldfd, REMOTEFILE , O_RDONLY);
   /* re-construct state, by seeking to the correct offset. */
    if (newfd >= 0)
      lseek(newfd, thdl->curr_offset, SEEK_SET); 
    (thdl->nr)++;
    return(newfd);
}

int main(int argc, char *argv[])
{
    int status;
    int fd;
    int fd2;
    int fd3;
    Handle hdl;
    char buf[80];
    int i;

    hdl.nr = 0;
    hdl.curr_offset = 0;
    /* open a connection */
    fd = ha_open(REMOTEFILE, O_RDONLY,recover_conn, 
               (void *)&hdl, 0);
    if (fd < 0) {
        printf("could not open file\n");
        exit(-1);
    }
    fd2 = open(REMOTEFILE, O_RDONLY);
    printf("trying to read from file using fd %d\n",fd);
    printf("before sleeping first time\n");
    status = read(fd,buf,15);
    if (status < 0)
        printf("error: %s\n",strerror(errno));
    else {
        for (i=0; i < status; i++)
            printf("%c",buf[i]);
        printf("\n");
   /*
    update state of the connection
    this is a kind of checkpointing method.
    we remember state, so that the recovery functions
    have an easier time.
   */
        hdl.curr_offset += status;
    }

    fd3 = ha_dup(fd);
    sleep(18); 
   /*
    sleep for some arbitrary period
    this could be some other computation
    or some other blocking operation, which gives
    a window within which the server might fail
   */

   /* reading from dup-ped fd */
    printf("trying to read from file using fd %d\n",fd);
    printf("after sleeping\n");

   /*
    if the read initially fails
    it will recover, re-open and seek to the right spot!!
   */
    status = read(fd,buf,15);
    if (status < 0)
        printf("error: %s\n",strerror(errno));
    else {
        for (i=0; i < status; i++)
            printf("%c",buf[i]);
        printf("\n");
        hdl.curr_offset += status;
    }
    printf("trying to read from file using fd %d\n",fd2);
   /*
    try it again.. this time using the copy.
    recovery will again happen upon failure,
    automatically re-connecting/seeking etc.
   */
    status = read(fd2,buf,15);
    if (status < 0)
        printf("error: %s\n",strerror(errno));
    else {
        for (i=0; i < status; i++)
            printf("%c",buf[i]);
        printf("\n");
    }
    printf("total recoveries, %d\n",hdl.nr);
    ha_close(fd);
    close(fd2);
    exit(0);
}