• Aucun résultat trouvé

4.2 Snapshot partiel

5.1.4 La simulation BG étendue

Cette section étend les algorithmes précédents pour fournir une implémentation de la simulation BG étendue. Notre but est d’obtenir une simulation aussi simple que possible. Pour cela, nous procédons de manière incrémentale en enrichissant la simulation BG classique. L’implémentation proposée utilise le même objet snapshot MEM et la même opération sim_writei,j() (figure 5.3) que la simulation BG

classique. Elle utilise aussi le même tableau SAFE _AG[1..n, 0...] constitué d’objets safe_agreement. Elle présente les objets partagés additionnels utilisés, les principes sur lesquels se base la simulation de mem.snaspshot() par un simulateur qi pour un processus simulé pj ainsi que l’algorithme (noté

5.1.4.1 Les objets partagés additionnels

En plus de MEM et SAFE _AG[1..n, 0...], la mémoire partagée par les simulateurs q1, . . . , qt+1

contient les objets suivants.

– ARBIT ER[1..t + 1, 0...] est un tableau d’objets de type arbiter. Le propriétaire des objets ARBIT ER[j, −] est le simulateur qj (1 ≤ j ≤ t + 1).

L’objet ARBIT ER[j, snapsn] est utilisé par un simulateur qiquand il simule son snapsn-ième

invocation mem.snapshot() pour le processus simulé pj pour 1 ≤ j ≤ t + 1. (Comme nous le

verrons, quand t + 1 < j ≤ n, la simulation de mem.snapshot() pour pj ne nécessite pas l’aide

d’un objet arbiter.)

– ARB_VAL[1..t+1, 0...][0..1] est un tableau de registres atomiques. La paire de registres atomiques ARB_VAL[j, snapsn][0..1] est associée à l’objet ARBIT ER[j, snapsn].

Le but de ARB_VAL[j, snapsn][1] est de contenir la valeur qui doit être renvoyée pour la snapsn- ième invocation mem.snapshot() par le processus simulé pjsi le propriétaire qjest désigné comme

gagnant par l’objet ARBIT ER[j, snapsn] correspondant. Si le propriétaire qjn’est pas le gagnant,

la valeur qui doit être renvoyée est celle stockée dans ARB_VAL[[j, snapsn][0].

5.1.4.2 L’opération e_sim_snapshoti,j()

L’algorithme enrichi Le code de l’algorithme qui implémente l’opération e_sim_snapshoti,j() exécu- tée par qipour simuler une opération mem.snapshot() invoquée par pjest décrite dans la figure 5.5. Ses

quatre premières lignes et sa dernière ligne sont exactement les mêmes que celles de la figure 5.4. Les lignes 05-06 sont remplacées par les nouvelles lignes N01-N11 qui constituent l’“addition” qui permet de passer de la simulation BG classique à la simulation BG étendue.

Principe de base Chaque processus pj(1 ≤ j ≤ n) est simulé par chaque simulateur qi(1 ≤ i ≤ t + 1)

comme dans la simulation BG classique, mais chaque processus simulé pj tel que 1 ≤ j ≤ t + 1 est

associé à exactement un simulateur qui est son “propriétaire” : qiest le propriétaire de pj si j = i (et donc

aussi le propriétaire des objets ARBIT ER[j, −] correspondants). Le but est, pour chaque snapsn ≥ 0, d’associer une seule valeur renvoyée pour les snapsn-ièmes invocations de e_sim_snapshoti,j() par les

simulateurs. L’idée est d’utiliser la notion de propriétaire pour “court-circuiter” l’utilisation de l’objet SAFE_AG[j, snapsn] dans des circonstances appropriées.

L’opération e_sim_snapshoti,j() pour les processus simulés pjtels que t + 2 ≤ j ≤ n est exactement

la même que sim_snapshoti,j(). Cela apparait dans les lignes N01-N02 qui sont les mêmes que les lignes 06-07 de la figure 5.4 (dans ce cas, il n’y a pas de notion de propriétaire).

Les nouvelles lignes N03-N10 traitent le cas des processus simulés qui ont un propriétaire, c’est-à-dire les processus p1, . . . , pt+1. L’idée est la suivante : si qi ne crashe pas, pine doit pas crasher. De cette

manière, si qiest correct, piterminera toujours quel que soit le comportement des autres simulateurs. Pour

cela, qi d’un coté et tous les autres simulateurs de l’autre sont en compétition pour définir la valeur du

snapshot renvoyée par les snapsn-ièmes invocations e_sim_snapshoti,j() effectuées par chacun d’entre

eux. Pour atteindre ce but, les objets ARBIT ER[j, snapsn] et ARB_VAL[j, snapsn] sont utilisés de la manière suivante.

Tous les simulateurs invoquent ARBIT ER[j, snapsn].arbitratei,j() (à la ligne N04 si qi est le

propriétaire, à la ligne N09 s’il ne l’est pas). Selon les spécifications du type arbiter, ces invocations ne doivent pas renvoyer des valeurs différentes et terminent au moins quand qjest correct et invoque cette

opération (comme indiqué dans la spécification, il y a d’autres cas où les invocations doivent terminer). Finalement, la valeur renvoyée indique si le propriétaire est le gagnant (1) ou non (0).

Si le gagnant est le propriétaire qj, la valeur renvoyée par les snapsn-ièmes invocations de l’opération

e_sim_snapshoti,j() (une invocation par simulateur) est la valeur inputj calculée par le propriétaire.

Cette valeur est stockée dans le registre atomique ARB_VAL[j, snapsn][1] (ligne N03).

Si le propriétaire n’est pas le gagnant, la valeur renvoyée est celle déterminée par les autres simu- lateurs qui ont invoqué SAFE _AG[j, snapsn].proposei(inputi) et SAFE _AG[j, snapsn].decidei()

(lignes N07 et N08). La valeur qu’ils ont calculé a été déposée dans ARB_VAL[j, snapsn][0] (ligne N08).

Il est important de remarquer que qjn’invoque pas proposej() et decidej() pour le processus dont il

est propriétaire. De plus, le simulateur qj est le seul qui peut écrire dans ARB_VAL[j, snapsn][1] tandis

que les autres simulateurs ne peuvent écrire que dans ARB_VAL[j, snapsn][0].

operation e_sim_snapshoti,j() :

(01) smi← MEM .snapshot() :

(02) for each y : 1 ≤ y ≤ n : do inputi[y] = smi[s, y].value

(03) where ∀x : 1 ≤ x ≤ t + 1 : smi[s, y].sn ≥ smi[x, y].sn end for ;

(04) snap_sni[j] ← snap_sni[j] + 1 ; let snapsn = snap_sni[j] ;

(N01) if (j > t + 1) then enter_mutex ; SAFE _AG[j, snapsn].proposei(inputi) ; exit_mutex ;

(N02) res← SAFE _AG[j, snapsn].decidei()

(N03) elseif (i = j) then ARB_VAL[j, snapsn][1] ← inputi;

(N04) enter_mutex ; win ← ARBIT ER[j, snapsn].arbitratei,j() ; exit_mutex ;

(N05) if (win = 1) then res ← inputi

(N06) else res ← ARB_VAL[j, snapsn][0] end if ;

(N07) else enter_mutex ; SAFE _AG[j, snapsn].propose(inputi) ; exit_mutex ;

(N08) ARB_VAL[j, snapsn][0] ← SAFE _AG[j, snapsn].decidei() ;

(N09) r← ARBIT ER[j, snapsn].arbitratei,j() ;

(N10) res← ARB_VAL[j, snapsn][r]

(N11) end if ; (07) return(res).

FIGURE5.5 – L’opération e_sim_snapshoti,j() exécutée par qipour simuler mem.snapshot() invoquée

par pj

Pour résumer, si un simulateur qi crashe, il entraine le crash d’au plus un processus simulé grâce

à l’utilisation de l’exclusion mutuelle sur les invocations de propose() des objets safe_agreement. Si le simulateur qi crashe, 1 ≤ i ≤ t + 1, du point de vue des processus simulés, il peut n’entrainer

(1) aucun crash (si il crashe en dehors d’une section critique), (2) le crash de pi (si il crashe durant

l’exécution de arbitratei,j() dans la section critique de la ligne N04), (3) le crash d’un processus pjtel

que 1 ≤ j 6= i ≤ t + 1 (ceci ne peut arriver que si qj a déjà crashé sans entrainer le blocage de pj, et

qi crashe dans la section critique de la ligne N08), ou (4) le crash d’un des processus pt+2, ..., pn(si il

crashe à la ligne N01 dans la section critique).

t-Résilience vs terminaison sans-attente Étant donné un algorithme de simulation BG dans lequel un processus simulé pj (1 ≤ j ≤ t + 1 ≤ n) ne peut être bloqué indéfiniment que si le simulateur qj crashe

et une tâche t-résiliente, Gafni montre dans [55] la tâche sans-attente équivalente sur t + 1 processus.