• Aucun résultat trouvé

P s(P ).Qs+PR(s)∈Ra(M ),s∈MR(s).P ′+Pf s(P ).Qfs − R(t, S) | P ′′(M′′, F′′) t ∈ M′′, P′′ ∈ S P′ | P′′ − t(P) (replicate update(s)) Lorsqu'un processus émet une réplication, il n'est pas modié mais tous les processus destinataires et pour lesquels l'état est créé reçoivent une mise à jour de l'état, si elle est autorisée pour l'émetteur.

P s(P ).Qs+PR(s)∈Ra(M ),s∈MR(s).P ′+Pf s(P ).Qfs − R(t, S) | P ′′(M′′, F′′) t /∈ M′′, f t∈ F′′, P′′ ∈ S P′ | P′′ − f t(P′) (replicate create(s)) Lorsqu'un processus émet une réplication, il n'est pas modié mais tous les processus destinataires et pour lesquels l'état n'est pas créé reçoivent une création d'état, si elle est autorisée pour l'émetteur.

5.5 Recettes de cuisine

Nous donnons ici quelques utilisations typiques de notre modèle pour des situations fréquemment rencontrées.

Comment obtenir une exécution reproductible Les facteurs suscep- tibles d'introduire de la non-reproductibilité dans l'application sont les tâches de la couche supérieure préemptive de notre modèle.

Dans le cas où aucune bibliothèque externe au framework n'est utilisée, ces tâches sont donc principalement les modications d'états provenant de réplications par des hôtes distant, ou les modications d'états provenant des commandes de l'utilisateur de l'application.

Pour mettre au point l'application, on peut donc scénariser ces mises à jour. De même, si une erreur se produit, pour peu qu'une trace soit gardée des

événements réseau et commandes utilisateur, il est possible de la reproduire et donc de faciliter sa correction.

Comment terminer précocement un calcul devenu obsolète Un ré- exe peut correspondre à un calcul lourd dont le résultat peut devenir ob- solète avant qu'il ne soit terminé : par exemple, un calcul de dead-reckoning entamé devient nalement inutile quand une nouvelle mise à jour de la posi- tion extrapolée arrive.

Il peut être judicieux de dédier un état particulier pour vérier si le cal- cul en cours est toujours valide. Dans notre exemple, la mise à jour de la position peut être suivie par le déclenchement d'un ordonnançable modiant cet état. Le réexe correspondant au calcul de Dead-Reckoning peut utili- ser régulièrement l'instruction ash an de terminer le calcul s'il est devenu obsolète.

Comment donner une priorité d'accès aux ressources à un traite- ment particulier Le modèle que nous avons décrit étant équitable, cette notion n'a de sens qu'en ce qui concerne le temps de calcul alloué à chaque ré- exe. On ne peut donc jouer qu'avec la réduction du nombre des instructions cooperate.

Comment modéliser une exécution de réexe du style message Il sut de ne jamais utiliser l'instruction ash, an de ne pas perdre la valeur initiale de l'état représentant le message.

Comment s'assurer qu'un état concerné par un réexe s'exécute avec une valeur à jour pour cet état La solution est de l'ordre de la conception des états de l'application. Nous avons vu que selon la sémantique de l'ordonnancement des réexes, on a la garantie qu'un état ne peut pas être modié par un autre réexe entre une instruction ash et une instruction cooperate.

Il sut de dénir l'état en question de façon à ce qu'il soit local à l'appli- cation, ne faisant pas partie de l'état global du jeu et donc non susceptible d'être modié directement par une réplication distante, et qu'il ne puisse

5.5. RECETTES DE CUISINE 153 également pas être modié par les autres processus de la couche supérieure préemptive.

Cette dénition ne réduit pas le champ des possibilités, puisque l'état pourra être indirectement modié par des réplications distantes, mais en utilisant un ordonnançable réagissant à la modication d'un autre état ré- pliqué : l'ordonnançable eectuant la modication de l'état et déclenché par la modication d'un autre état obtenu par réplication passera alors par l'or- donnanceur équitable des réexes.

Chapitre 6

Implémentation

Le Fill-In-The-Gaps Toolkit est un prototype destiné à illustrer notre approche. Il implémente le modèle de comportement d'une application dis- tribuée selon la sémantique étudiée au chapitre précédent, et peut se découper en plusieurs parties.

 Un calcul local, comprenant l'ordonnanceur travaillant sur des copies d'états, exécute les réexes des ordonnançables selon la sémantique que nous avons dénie. Les réexes sont décrits par l'utilisateur dans le langage Java, qui est aussi le langage de l'implémentation. L'utilisa- teur dispose également des instructions ash (mise à jour du contexte d'exécution local), update (mise à jour des données propres d'un état), cooperate (interruption d'exécution temporaire), create (création d'un état) et destroy (destruction d'un état).

 Un ensemble hiérarchisé de classes abstraites et d'interfaces permet de dénir les composants de l'application : états, ensembles d'états dupli- cata et ordonnançables. Cet ensemble permet également de dénir les briques de base nécessaires à la constitution des modèles de réplication, les portées et les propriétés de communication.

 La carte de l'application, rassemble tous les composants de l'application ainsi que l'état local du jeu.

Nous avons déni également quelques éléments de départ pour une biblio- thèque de briques de base (les Gaps du Fill-In-The-Gaps Toolkit) an de pouvoir montrer comment utiliser le framework.

Nous avons rané notre prototype jusqu'à en obtenir une version qui prend en entrée des éléments pouvant être générés automatiquement à partir d'une description scriptée de l'assemblage des états et des ordonnançables, et du code des réexes. Nous montrons ainsi comment le framework peut s'intégrer ultérieurement dans un outil futur.

Ce chapitre présente ce travail. Après avoir expliqué le choix du langage de l'implémentation, nous montrons comment le développeur peut actuellement l'utiliser, en expliquant quels sont les aspects que nous pensons automatiser à partir d'un outil de développement futur. Nous dédions ensuite trois sections à la présentation de la façon dont nous avons implémenté les trois ensembles fonctionnels du framework : l'ordonnanceur, la hiérarchie des composants, et la carte de l'application. Pour nir, nous donnons un exemple simple d'appli- cation réalisé à l'aide du framework et de quelques éléments de la bibliothèque associée.

6.1 Un prototype en Java

Nous avons choisi de développer le prototype en Java. Les raisons de ce choix sont tout d'abord que l'auteur de cette thèse apprécie ce langage. Mais il y a aussi des raisons moins subjectives.

Tout d'abord, les outils de développement pour ce langage, et ses bi- bliothèques très intégrées en font en langage de choix pour un prototypage rapide, à but démonstratif. Le ramasse-miette, même s'il n'est pas une arme ultime contre les fuites mémoires, permet un grand confort de programma- tion. Nous avons eu besoin des qualités d'introspection du langage, et avons avantageusement proté de son modèle orienté objet pour factoriser du code, et mettre à prot polymorphisme et liaison tardive.

Ce choix n'a donc pas été dicté, comme souvent, par des impératifs de portabilité : en eet, la bibliothèque des threads de Java est très complexe à utiliser si on veut réaliser une application portable. Comme cela n'était pas notre objectif, nous sommes partis du principe que nous disposions d'une machine virtuelle utilisant un modèle de thread préemptif. De même, nous ne nous sommes pas arrêtés aux problèmes éventuels de performances que nous pourrions éventuellement rencontrer en utilisant une stratégie d'ordon-

6.2. LE POINT DE VUE DE L'UTILISATEUR 157