Pour mettre en oeuvre le TP, il convient d'extraire les sources du TP et de taper la commande make ce qui aura pour conséquence de construire le programme main.
Chaque noeud logique exécute le même programme nommé main. Celui-ci requiert de passer un numéro de noeud en argument pour différencier ses différentes instances. Il peut s'accompagner éventuellement d'autres arguments de configuration. Pour mettre en oeuvre le système réparti, il faut ouvrir trois sessions et lancer dans chacune d'elles le programme main avec trois numéros de noeud différents allant de 1 à 3. Par exemple :
./main 1
Par défaut, la diffusion adopte la politique dite simple qui ne respecte absolument pas l'ordre total causal.
Changer de politique de diffusion s'obtient en rajoutant sur la ligne de commande le paramètre suivant :
./main 1 -p=nom_du_protocole
où le nom du protocole peut valoir :
Dans le cadre du TP, nous n'avez qu'à modifier les composants dits protocolaires c'est à dire les fichiers protocols-*.adb dans lesquels se trouvent décrits les politiques de diffusion qui se trouvent dans un état compilable mais incomplet. Les descriptions ci-dessous permettent de comprendre les interactions entre les différents composants applicatifs, protocolaires et de transport. Tous les fichiers sont commentés et permettent par ailleurs de comprendre l'organisation du logiciel.
main se charge d'appeler la procédure d'initialisation du
système Initialize décrite dans common.adb.
En fonction de son numéro passé en argument sur la ligne de commande,
un noeud va se charger d'attendre que les opérations des noeuds
précédents se soient exécutées, puis va demander la diffusion de son
opération. Pour ce faire, il alloue un message et le remplit. Par
exemple, pour le noeud 1, le message contiendra l'opération d'addition
avec un opérande de 1.
Emballer un entier (Integer en Ada) I dans un message M
s'obtient par :
Le paquetage Application contient les callbacks qui
seront appelés lorsque les composants protocolaires délivreront une
requête aux composants applicatifs. Il se charge d'effectuer les
calculs sur la variable partagée et également signale au noeud qu'il
peut procéder à l'exécution de ses propres requêtes.
Le paquetage Common se charge notamment d'initialiser le
système ce qui veut dire :
Par ailleurs, le paquetage Common définit un certain nombre de
types comme Node_Type qui décrit les numéros de noeuds allant
de First_Node (= 1) à Last_Node (=3).
Ce paquetage fournit les fonctionnalités d'affichage nécessaires à la
mise au point. Les procédures prennent en paramètre un paramètre
précisant dans quelle circonstance le texte doit être affiche. C'est à
dire s'il ne doit être affiché que lorsque le mode Verbose a
été activé sur la ligne de commande (-v).
Le fichier nodes contient les adresses IP à utiliser par chacun
des noeuds, le noeud N utilisant la Nième adresse du
fichier.
Ce paquetage définit une classe abstraite (type ... abstract
tagged) Protocol_Type dont dérivent toutes les classes
mettant en oeuvre les politiques de diffusion. Cette classe requiert
l'existence de deux méthodes Broadcast et Receive. La
variable Current_Protocol fait référence au protocole
sélectionné.
Le paquetage LClock contient les structures de données
nécessaires à la gestion des horloges de Lamport et surtout celles
nécessaires à la gestion des messages de la politique de diffusion
fondée sur les horloges de Lamport.
Le paquetage MClock contient les structures de données
nécessaires à la gestion des horloges de Mattern et surtout celles
nécessaires à la gestion des messages de la politique de diffusion
fondée sur les horloges de Mattern.
Le paquetage Tables fournit des fonctionnalités de gestion de
table d'éléments de type quelconque. Il permet notamment de gérer des
tables triées selon une fonction de comparaison fournies lors de leur
initialisation. Si l'initialisation ne comporte pas de fonction de
comparaison alors la table reste non-triée lors de l'ajout d'un
élément. Ces fonctionnalités seront utiles pour la gestion des
messages en attente.
Le paquetage Semaphores fournit des fonctionnalités classiques
de synchronisation nécessaires pour la protection de données comme les
horloges contre des accès concurrents.
La paquetage Messages permet de gérer un ensemble de
messages. Globalement, un message se rapproche d'un tampon ou flux
d'octets dans lequel on peut stocker des données de types différents
sous forme d'une représentation donnée, ici leur représentation en
mémoire. Dans notre cas, un message permettra de construire le message
qui sera envoyé sur le réseau. Pour manipuler ces messages, nous
disposerons de procédures d'écriture ou de lecture d'une valeur dans
un message. Pour chacun des types du TP, nous fournissons une
procedure d'écriture Append et une procédure de lecture
Extract. Par exemple:
En dehors des routines d'allocation et de désallocation de messages,
on peut connaitre la taille d'un message ou copier à la fin d'un message
un autre message Append_Message.
Le paquetage Transport se charge de mettre en oeuvre un
protocole de transport qui se caractérise par des temps de latence
aléatoire même lors d'une communication sur un même noeud. Il offre
deux procédures permettant de diffuser et d'envoyer un message.
Par ailleurs, chaque message reçu par le composant de transport est
délivré auprès de la partie supérieure c'est à dire le composant
protocolaire par l'intermédiaire d'un processus léger (même lorsqu'il
s'agit d'un message en provenance du noeud lui-même).
Composants applicatifs
Allocate (Message);
case My_Node is
when 1 =>
Append_Request ((Add, 1), Message);
when 2 =>
Append_Request ((Mul, 2), Message);
when 3 =>
Append_Request ((Sub, 2), Message);
when others =>
null;
end case;
Broadcast (Current_Protocol.all, Message);
Append_Integer (I, M);
Dans le cadre, emballer une valeur V de type T dans
un message M s'effectue grâce à l'instruction :
Append_T (V, M);
Pareillement, lire une valeur V de type T dans un
message M s'effectue grâce à l'instruction :
Extract_T (V, M);
L'appel de méthode Broadcast (Current_Protocol.all, Message);
demande aux composants protocolaires d'envoyer le message en utilisant
le protocole de diffusion sélectionné éventuellement par un argument
sur la ligne de commande.
Composants protocolaires
Composants de transports
Append_MClock (C, M);
permet d'écrire une valeur C de type MClock dans un
message M alors que
Extract_MClock (C, M);
permet de lire une valeur C de type MClock dans un
message M.