Transis Documentation

By Esti Yeger Lotem

Submitted as a Lab Project at November 28, 1995


Contents:

Transis Home Page

This Is Root

About this Document

This document is a beginner's course on the Transis environment. It supplements The Transis User Tutorial by Dalia Malki. It will therefore not explain the syntax of commands, but more about their semantics. It will also give some typical examples on how to use the Transis approach in distributed applications, and describe several pitfalls that can be avoided.

This document was submitted as a lab project in the High Availability Lab, Computer Science Department, The Hebrew University, Jerusalem, Israel.

Acknowledgments to all the lab members and other faithful readers who contributed ideas, pointed out vague issues, and spent time reading this document and commenting on it.

If you have any comments or questions, please mail.

Introduction to Transis

Transis is a multicast communication layer that facilitates the development of fault tolerant applications in a network of machines.
It supports process group communication:
A process group is a group of processes conveniently identified by a name (a string) selected by the user.
Messages addressed to the group are received by all group members (under specific constraints). Thus, the sender is not required to from identify all the targets of the message explicitly, or find the network route to them.
Transis also supports a membership service:
If processes are added to a group or deleted from it (due to process crash, changes in the network or the user's preference), Transis will report the change to all active group members, while keeping consistency among them (more about consistency in Virtual and Extended Virtual Synchrony).

To understand what group communication is, consider the following example. Imagine that you and your friends are going on a picnic, and each person has to bring something from the following list - drinks, salads, bread and rolls, cake, dishes, silver ware, and so forth. The problem is that you don't have time to meet and discuss things, so you must use some communication mode - probably the telephone.

This would usually take endless phone calls in which only two persons can communicate at once. Information like "is anyone bringing a cake" must be exchanged and repeated in many calls - quite awkward. Transis, on the other hand, is similar to a conference call. The group communication facility allows you and your friends to form the "conference." Calling this new entity will make the phone ring at all your friends' homes, and after they all pick up their phones, everyone will be able to hear everyone and speak to everyone as if you were all in the same room.

Using TCP for group communication is similar to using simple phone calls in the above example - it is possible but rather complicated: A socket should be installed between each two processes, and messages would have to be repeated over various channels in order to inform everyone.

Transis, in contrast, takes advantage of the multicast facility available in current networks. Thus, much like in the above example, a message is only sent once. Moreover all-or-none delivery semantics are guaranteed, message losses and transient network failures are transparent, and message ordering is supplied.

In TCP, membership changes (such as when connection between two computers fails) must be managed by the user, through a timeout mechanism of some sort. Hence user tasks become much more complicated. Transis, on the other hand, reports membership changes, while guaranteeing additional information.

an application example - user.c

The following is a very simple application written over Transis, that demonstrates Transis facilities.
(It can be found in /cs/transis/src/ring/user.c.)

When zzz_user.c is activated, the process contacts Transis: It creates for itself a singleton group, and receives a `mailbox' to which messages will arrive. Then you can do the following:

A more detailed explanation on the different facilities may be found in Transis: The Transis User Tutorial

ZZZ_User.c


#include stdio.h
#include "zzz_layer.h"
#include "sim_layer.h"
 
#define MAX_MEMBERS 100
# define USAGE "Usage : %s [-sim] [-simname ] [-sig] [-name ] [-group_service <0/1>] \n", argv[0]

#define TEXT "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzzaabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz"

static zzz_mbox_cap	my_mbox;
static mbox_cap	        ha_mbox;

static char	send_buf[40000];
static char	recv_buf[40000];
static int     	num_send = 0;
static int	async=0;

void    	Print(void);
void 		Handle_user(int, void *);
void 		Handle_mess(int, void *);

main(int argc, char **argv)
{

	int sim_requested = 0;
	int sig_requested = 0;
        int flag = 1;
	char *stack = NULL; /* default layer stack will be used */
	char **parms;
        char *my_name = NULL;
        char *sim_name = NULL;
 
	/* If "-sim" was specified the stack of layers will
	 * contain the SIM layer before the default layer.
	 */
	parms = argv+1;
	while (argc  > 1) {
		if (!strcmp("-sim", parms[0])) {
			argc--;
			parms++;
			sim_requested = 1;
		}
		else if (!strcmp("-sig", parms[0])) {
			argc--;
			parms++;
			sig_requested = 1;
		}
                else if (!strcmp("-name", parms[0])){
                        argc--;
                        parms++;
                        if(argc == 1){
                           printf(USAGE);
                           exit(1);
			}
                        my_name = parms[0];
                        parms++;
                        argc--;
		}
                else if (!strcmp("-simname", parms[0])){
                        argc--;
                        parms++;
                        if(argc == 1){
                           printf(USAGE);
                           exit(1);
			}
                        sim_name = parms[0];
                        parms++;
                        argc--;
		}
                else if (!strcmp("-group_service", parms[0])){
                        argc--;
                        parms++;
                        if(argc == 1){
                           printf(USAGE);
                           exit(1);
			}
                        flag = atoi(parms[0]);
                        parms++;
                        argc--;
		}
		else break;
	}
 
	if (sim_requested || sig_requested) {
		/* Concatinate "SIM:" and/or "SIG:"
		 * with the default layer stack. 
		 */
		stack = (char *) malloc 
			(strlen("SIM:")*sim_requested +
			 strlen("SIG:")*sig_requested +
			 strlen(zzz_DEFAULT_LAYERS) + 1);
		if (stack == NULL)
			error (1, 0, "memory problem");
 
		if (sim_requested && sig_requested)
			strcpy(stack, "SIG:SIM:");
		else if (sim_requested)
			strcpy(stack, "SIM:");
		else 
			strcpy(stack, "SIG:");
		strcat(stack, zzz_DEFAULT_LAYERS);
	}

	if (argc > 1) {
		printf(USAGE);
		exit(1);
	}

        if((sim_name) && (sim_requested)){
           SIM_Set_Name(NULL, sim_name); 
	}

        if(!my_name)
            my_name = argv[0];

        my_mbox = zzz_Connect(my_name, stack, flag);

        if (my_mbox == NULL) 
                error(1,0,"connect failed");

	ha_mbox = zzz_Focus (my_mbox, "HA");

        strcpy(send_buf, "hello");
	send_buf[3000] = 'a';

 	E_init();

	E_add_sock( (long)0, Handle_user, USER_PRIORITY, NULL);
        Print();
	printf("\nenter command: ");
	fflush(stdout);
	E_main_loop();
}


void Handle_user(int dummy1, void *dummy2)
{
        char    buf[80];
        char    command[80];
        char    *name;
        int     num_args;
        int     l,i;
	int     recv_type ;
	view    *gview;

	if (gets(buf) == NULL)
		exit(0);


	name = (char *) malloc (80) ;

	num_args = sscanf(buf,"%s%s", command, name );
	if (name[0]=='@')
	  name = TEXT;
	if (num_args == 1) {
		if (!strcmp(command,"r")) {
			printf("attempt receive (blocking)\n");
			Handle_mess(-1, 0);
		} else if (!strcmp(command,"p")) {
			printf("num bytes: %d\n",
                                        zzz_Poll(my_mbox) );
		} else if (!strcmp(command,"q")) {
			printf("Have a nice night\n");
			exit(0);
		} else if (!strcmp(command,"a")) {
			if (async) {
				zzz_Remove_Upcall(my_mbox);
				async = 0;
			} else {
				zzz_Add_Upcall(my_mbox, Handle_mess, 
					      USER_PRIORITY, (void *) 1);
				async = 1;
			}
		} else if (!strcmp(command,"g")) {
			HA_Set_Group_Service(ha_mbox);
			printf("setting group service\n");
		} else if (!strcmp(command,"u")) {
			HA_Reset_Group_Service(ha_mbox);
			printf("reseting group service\n") ;
		} else {
			printf("Unrecognized command \n");
			Print();
		}
	} else if (num_args == 2 ) {
		if (!strcmp(command,"j") ) {
		  zzz_Join(my_mbox, name);
		} else if (!strcmp(command,"l") ) {
			zzz_Leave(my_mbox, name);
		} else if (!strcmp(command,"s") ) {
			sprintf(send_buf,"mess num %5d ",++num_send);
			l = zzz_VaSend(my_mbox, CAUSAL, 0, 
				      3500, send_buf, name, NULL);
			printf("send %d bytes\n", l);
		} else if (!strcmp(command,"b") ) {
			for(i=0; i<10; i++)
			{
				sprintf(send_buf,"mess num %5d ",++num_send);
				l = zzz_VaSend(my_mbox, CAUSAL, 0, 
					1000, send_buf, name, NULL);
				printf("send %d bytes\n", l);
			}
		} else {
			printf("Unrecognized command \n");
			Print();
		}
	}
	printf("\nenter command: ");
	fflush(stdout);
}

void
Handle_mess(int dummy1, void *param)
{
	int if_async = (int) param; /* 1 if called asynchronously */
	int i, recv_type ;
	view *gview;
	
	printf("\n-----------\n");
	printf("Handle_mess:");
	zzz_Receive(my_mbox, recv_buf, 40000, &recv_type, &gview);
	printf("message type is %d\n",recv_type) ;
	if( recv_type != VIEW_CHANGE)
	  printf("receive handler got mess %s\n", recv_buf);
	else {
		printf("group is %s\n", gview->members[0]) ;
		printf("no. of clients is %d\n", 
		       gview->nmembers); 
		for( i=1 ; i<= gview->nmembers ; i++ ) 
		  printf("%s ", gview->members[i]) ;
		printf("\n") ;
	}

	if (if_async) {
		printf("\nenter command: ");
		fflush(stdout);
	}
}

void
Print()
{
        printf("User commands : \n");
        printf("    j  -- join\n");
        printf("    l  -- leave\n");
        printf("    s  -- send\n");
        printf("    b  -- send burst of 10 msgs\n");
        printf("    r -- receive\n");
        printf("    p -- poll\n");
        printf("    a -- toggle async mode\n");
	printf("    g -- set group service\n") ;
	printf("    u -- reset group service\n") ;
        printf("    q -- quit\n");
}

Contents