Aller au contenu

Modèle de cohérence

Un article de Wikipédia, l'encyclopédie libre.

En Informatique, les modèles de cohérence sont utilisés dans les systèmes répartis comme les systèmes de mémoire partagée distribuée (DSM) ou les magasins de données distribuées (tels que les système de fichiers, les bases de données, les systèmes de réplication optimiste ou la mise en cache web). On dit que le système supporte un modèle donné si les opérations sur la mémoire suivent des règles spécifiques. Le modèle de cohérence des données spécifie un contrat entre le programmeur et le système, dans lequel le système garantit que si le programmeur suit les règles, la mémoire sera cohérente et les résultats de la lecture, de l'écriture ou de la mise à jour de la mémoire seront prévisibles. Ceci est différent de la cohérence, qui se produit dans les systèmes avec ou sans cache, et qui est la cohérence des données par rapport à tous les processeurs. La cohérence consiste à maintenir un ordre global dans lequel les écritures dans un emplacement unique ou une variable unique sont vues par tous les processeurs. La cohérence concerne l'ordre des opérations sur plusieurs emplacements par rapport à tous les processeurs.

Les langages de programmation de haut niveau, tels que C++ et Java, maintiennent partiellement le contrat en traduisant les opérations de mémoire en opérations de bas niveau de manière à préserver la sémantique de la mémoire. Pour respecter le contrat, les compilateurs peuvent réorganiser certaines instructions de mémoire, et les appels de bibliothèque tels que pthread_mutex_lock() encapsulent la synchronisation requise[1].

La vérification de la cohérence séquentielle par vérification de modèles est indécidable en général, même pour les protocoles de cohérence de cache à état fini[2].

Les modèles de cohérence définissent des règles pour l'ordre apparent et la visibilité des mises à jour, et se situent sur un continuum avec des compromis[3].

Supposons que le cas suivant se produise[3] :

  • La ligne X est répliquée sur les nœuds M et N
  • Le client A écrit la ligne X au nœud M
  • Après une période de temps t, le client B lit la ligne X du nœud N

Le modèle de cohérence doit déterminer si le client B voit l'écriture effectuée par le client A ou non.

Il existe deux méthodes pour définir et classer les modèles de cohérence : l'émission et la vue.

Émission :
La méthode d'émission décrit les restrictions qui définissent comment un processus peut émettre des opérations.
Vue
La méthode de vue définit l'ordre des opérations visibles par les processus.

Par exemple, un modèle de cohérence peut définir qu'un processus n'est pas autorisé à émettre une opération tant que toutes les opérations émises précédemment ne sont pas terminées. Les différents modèles de cohérence appliquent des conditions différentes. Un modèle de cohérence peut être considéré comme plus fort qu'un autre s'il exige toutes les conditions de ce modèle et plus encore. En d'autres termes, un modèle comportant moins de contraintes est considéré comme un modèle de cohérence plus faible.

Ces modèles définissent la manière dont le matériel doit être disposé et, à un haut niveau, la manière dont le programmeur doit coder. Le modèle choisi affecte également la manière dont le compilateur peut réordonner les instructions. En général, si les dépendances de contrôle entre les instructions et si les écritures au même emplacement sont ordonnées, alors le compilateur peut réordonner selon les besoins. Cependant, avec les modèles décrits ci-dessous, certains peuvent permettre de réordonner les écritures avant les chargements, d'autres non.

Cohérence stricte

[modifier | modifier le code]

La cohérence stricte est le modèle de cohérence le plus fort. Dans ce modèle, l'écriture d'une variable par n'importe quel processeur doit être vue instantanément par tous les processeurs.

Le diagramme de modèle strict et les diagrammes de modèle non strict décrivent la contrainte de temps - instantanée. Cela peut être mieux compris comme si une horloge globale était présente, dans laquelle chaque écriture doit être reflétée dans tous les caches du processeur avant la fin de cette période d'horloge. L'opération suivante ne doit se produire que dans la période d'horloge suivante.

Séquence Modèle strict Modèle non-strict
P1 P2 P1 P2
1 W(x)1 W(x)1
2 R(x)1 R(x)0
3 R(x)1

Il s'agit du modèle le plus rigide. Dans ce modèle, le résultat attendu par le programmeur sera reçu à chaque fois. Il est déterministe. Sa pertinence pratique est limitée à une expérience de pensée et à un formalisme, car l'échange instantané de messages est impossible. Il ne permet pas de répondre à la question de la résolution des conflits en cas d'écritures concurrentes sur le même élément de données, car il suppose que les écritures concurrentes sont impossibles.

Cohérence séquentielle

[modifier | modifier le code]

Le modèle de cohérence séquentielle a été proposé par Lamport (1979). Il s'agit d'un modèle de mémoire plus faible que le modèle de cohérence stricte. L'écriture d'une variable ne doit pas nécessairement être vue instantanément, mais les écritures de variables par différents processeurs doivent être vues dans le même ordre par tous les processeurs. Comme défini par Lamport (1979)[4], la cohérence séquentielle est satisfaite si "le résultat de toute exécution est le même que si les opérations de tous les processeurs étaient exécutées dans un certain ordre séquentiel, et que les opérations de chaque processeur individuel apparaissent dans cette séquence dans l'ordre spécifié par son programme."

L'ordre du programme au sein de chaque processeur et l'ordre séquentiel des opérations entre les processeurs doivent être maintenus. Afin de préserver l'ordre séquentiel d'exécution entre les processeurs, toutes les opérations doivent sembler s'exécuter instantanément ou atomiquement par rapport à chaque autre processeur. Ces opérations doivent seulement "sembler" s'exécuter car il est physiquement impossible d'envoyer des informations instantanément. Par exemple, dans un système utilisant un seul bus partagé globalement, une fois qu'une ligne de bus reçoit une information, il est garanti que tous les processeurs verront cette information au même moment. Ainsi, le passage de l'information sur la ligne de bus achève l'exécution par rapport à tous les processeurs et semble avoir été exécuté. Les architectures sans cache ou les architectures avec cache dont les réseaux d'interconnexion ne sont pas instantanés peuvent contenir un chemin lent entre les processeurs et les mémoires. Ces chemins lents peuvent entraîner une incohérence séquentielle, car certaines mémoires reçoivent les données diffusées plus rapidement que d'autres.

La cohérence séquentielle peut produire des résultats non déterministes. En effet, la séquence des opérations séquentielles entre les processeurs peut être différente au cours des différentes exécutions du programme. Toutes les opérations de mémoire doivent se produire dans l'ordre du programme.

La linéarisabilité (également connue sous le nom de cohérence atomique) peut être définie comme la cohérence séquentielle avec la contrainte de temps réel.

Cohérence causale

[modifier | modifier le code]

La cohérence causale est un modèle d'affaiblissement de la cohérence séquentielle qui consiste à classer les événements en deux catégories : ceux qui sont liés par la causalité et ceux qui ne le sont pas.

Ce modèle relâche la cohérence séquentielle sur les écritures concurrentes d'un processeur et sur les écritures qui ne sont pas causalement liées. Deux écritures peuvent devenir causalement liées si une écriture sur une variable dépend d'une écriture précédente sur une variable quelconque et si le processeur qui effectue la seconde écriture vient de lire la première. Les deux écritures peuvent avoir été effectuées par le même processeur ou par des processeurs différents.

Comme dans la cohérence séquentielle, les lectures n'ont pas besoin de refléter les changements instantanément, mais elles doivent refléter tous les changements apportés à une variable de manière séquentielle.

Séquence P1 P2
1 W1(x)3
2 W2(x)5
3 R1(x)3

W1 n'est pas causalement lié à W2. R1 serait séquentiellement incohérent mais est causalement cohérent.[précision nécessaire][5]

Sequence P1 P2 P3 P4
1 W(x)1 R(x)1 R(x)1 R(x)1
2 W(x)2
3 W(x)3 R(x)3 R(x)2
4 R(x)2 R(x)3

W(x)1 et W(x)2 sont liés par un lien de causalité en raison de la lecture effectuée par P2 sur x avant W(x)2[5].

Cohérence du processeur

[modifier | modifier le code]

Afin de maintenir la cohérence des données et d'obtenir des systèmes de processeurs évolutifs où chaque processeur dispose de sa propre mémoire, le modèle de cohérence des processeurs a été élaboré[5]. Tous les processeurs doivent être cohérents dans l'ordre dans lequel ils voient les écritures effectuées par un processeur et dans la façon dont ils voient les écritures effectuées par différents processeurs au même endroit (la cohérence est maintenue). Cependant, ils n'ont pas besoin d'être cohérents lorsque les écritures sont effectuées par différents processeurs à des emplacements différents.

Chaque opération d'écriture peut être divisée en plusieurs sous-écritures dans toutes les mémoires. La lecture d'une de ces mémoires peut avoir lieu avant que l'écriture dans cette mémoire ne soit terminée. Par conséquent, les données lues peuvent être périmées. Ainsi, un processeur sous PC peut exécuter un chargement plus récent lorsqu'un stockage plus ancien doit être bloqué. L'ordre de lecture avant écriture, lecture après lecture et écriture avant écriture est toujours préservé dans ce modèle.

Le modèle de cohérence du processeur[6] est similaire au modèle de cohérence PRAM avec une condition plus forte qui définit que toutes les écritures sur le même emplacement mémoire doivent être vues dans le même ordre séquentiel par tous les autres processus. La cohérence du processeur est plus faible que la cohérence séquentielle mais plus forte que le modèle de cohérence PRAM.

Le système multiprocesseur DASH de Stanford met en œuvre une variante de la cohérence des processeurs qui est incomparable (ni plus faible ni plus forte) avec les définitions de Goodman[7]. Tous les processeurs doivent être cohérents dans l'ordre dans lequel ils voient les écritures d'un processeur et dans la façon dont ils voient les écritures de différents processeurs au même emplacement. Cependant, ils n'ont pas besoin d'être cohérents lorsque les écritures sont effectuées par différents processeurs à différents emplacements.

Cohérence de la RAM en pipeline, ou cohérence FIFO

[modifier | modifier le code]

La cohérence de la RAM pipelinée (cohérence PRAM) a été présentée par Lipton et Sandberg en 1988[8] comme l'un des premiers modèles de cohérence décrits. En raison de sa définition informelle, il existe en fait au moins deux implémentations subtilement différentes[7], l'une par Ahamad et al. et l'autre par Mosberger.

Dans la cohérence PRAM, tous les processus voient les opérations d'un seul processus dans le même ordre qu'elles ont été émises par ce processus, tandis que les opérations émises par des processus différents peuvent être vues dans un ordre différent par des processus différents. La cohérence PRAM est plus faible que la cohérence du processeur. La PRAM relâche le besoin de maintenir la cohérence d'un emplacement à travers tous ses processeurs. Ici, les lectures de n'importe quelle variable peuvent être exécutées avant les écritures dans un processeur. L'ordre de lecture avant écriture, lecture après lecture et écriture avant écriture est toujours préservé dans ce modèle.

Séquence P1 P2 P3 P4
1 W(x)1
2 R(x)1
3 W(x)2
4 R(x)1 R(x)2
5 R(x)2 R(x)1

Cohérence du cache

[modifier | modifier le code]

La cohérence du cache[6],[9] exige que toutes les opérations d'écriture sur un même emplacement mémoire soient effectuées dans un certain ordre séquentiel. La cohérence du cache est plus faible que la cohérence du processeur et incomparable avec la cohérence de la PRAM.

Cohérence lente

[modifier | modifier le code]
Mémoire lente

En cohérence lente[9], si un processus lit une valeur précédemment écrite dans un emplacement mémoire, il ne peut pas lire ultérieurement une valeur antérieure de cet emplacement. Les écritures effectuées par un processus sont immédiatement visibles pour ce processus. La cohérence lente est un modèle plus faible que la cohérence de la PRAM et du cache.

Exemple :

Le diagramme de la mémoire lente décrit un exemple de cohérence lente. Le premier processus écrit 1 à l'emplacement mémoire X puis écrit 1 à l'emplacement mémoire Y. Le second processus lit 1 à partir de Y puis lit 0 à partir de X même si X a été écrit avant Y.

Hutto, Phillip W., et Mustaque Ahamad (1990)[10] illustrent qu'avec une programmation appropriée, la mémoire lente (cohérence) peut être expressive et efficace. Ils mentionnent que la mémoire lente possède deux propriétés précieuses : la localité et le support de la réduction de la mémoire atomique. Ils proposent deux algorithmes pour présenter l'expressivité de la mémoire lente.

Les modèles suivants nécessitent une synchronisation spécifique par les programmeurs.

Ordonnancement faible

[modifier | modifier le code]

L'ordre et l'atomicité du programme sont maintenus uniquement sur un groupe d'opérations et non sur toutes les lectures et écritures. Cela découle de la compréhension du fait que certaines opérations de mémoire - telles que celles effectuées dans une section critique - ne doivent pas être vues par tous les processeurs - jusqu'à ce que toutes les opérations de la section critique soient terminées, par exemple. Il exploite également le fait que les programmes écrits pour être exécutés sur un système multiprocesseur contiennent la synchronisation nécessaire pour s'assurer que les courses de données ne se produisent pas et que les résultats SC sont toujours produits. Ainsi, dans l'ordonnancement faible, les opérations autres que les opérations de synchronisation peuvent être classées comme des opérations de données[11].

P1 P2
X = 1;
barrière
 
xready = 1;
barrière
while (!xready) {}; 
 
barrière
 
y = 2;

Les opérations de synchronisation signalent au processeur qu'il doit s'assurer qu'il a terminé et vu toutes les opérations précédentes effectuées par tous les processeurs. Afin de maintenir un ordre faible, les opérations d'écriture précédant une opération de synchronisation doivent être globalement effectuées avant l'opération de synchronisation. Les opérations présentes après une opération de synchronisation doivent également être effectuées uniquement après la fin de l'opération de synchronisation. Par conséquent, l'accès aux variables de synchronisation est séquentiellement cohérent et toute lecture ou écriture ne doit être effectuée qu'après la fin des opérations de synchronisation précédentes. La cohérence n'est pas relâchée dans ce modèle. Une fois ces exigences satisfaites, toutes les autres opérations de "données" peuvent être réorganisées.

Il y a une forte dépendance à la synchronisation explicite dans le programme. Pour les modèles d'ordonnancement faibles, le programmeur doit utiliser des instructions de verrouillage atomique telles que test-and-set, fetch-and-op, store conditional, load linked ou doit étiqueter des variables de synchronisation ou utiliser des barrières.

Cohérence de libération

[modifier | modifier le code]

Le modèle de cohérence de libération relaxe le modèle de cohérence faible en distinguant l'opération de synchronisation d'entrée de l'opération de synchronisation de sortie. Dans le modèle de cohérence faible, lorsqu'une opération de synchronisation doit être vue, toutes les opérations de tous les processeurs doivent être visibles avant que l'opération de synchronisation ne soit effectuée et que le processeur ne procède. Cependant, dans le cadre du modèle de cohérence de libération, lors de l'entrée dans une section critique, appelée "acquisition", toutes les opérations relatives aux variables de la mémoire locale doivent être terminées. Lors de la sortie, appelée "release", toutes les modifications effectuées par le processeur local doivent être propagées à tous les autres processeurs. La cohérence est toujours maintenue.

L'opération d'acquisition est un chargement/lecture qui est effectué pour accéder à la section critique. Une opération de libération est un stockage/écriture effectué pour permettre aux autres processeurs d'utiliser les variables partagées.

Parmi les variables de synchronisation, il est possible de maintenir la cohérence séquentielle ou la cohérence du processeur. Avec SC, toutes les variables de synchronisation concurrentes doivent être traitées dans l'ordre. En revanche, avec PC, une paire de variables concurrentes ne doit suivre que cet ordre. On peut permettre à des acquisitions plus jeunes de se produire avant des versions plus anciennes[12].

Cohérence de la saisie

[modifier | modifier le code]

Il s'agit d'une variante du modèle de cohérence de libération. Il nécessite également l'utilisation d'instructions d'acquisition et de libération pour indiquer explicitement une entrée ou une sortie dans une section critique. Toutefois, dans le cadre de la cohérence de saisie, chaque variable partagée se voit attribuer une variable de synchronisation qui lui est propre. De cette façon, ce n'est que lorsque l'acquisition concerne la variable x que toutes les opérations liées à x doivent être achevées par rapport à ce processeur. Cela permet d'effectuer des opérations concurrentes sur différentes sections critiques de différentes variables partagées. La simultanéité ne peut pas être vue pour les opérations critiques sur la même variable partagée. Un tel modèle de cohérence sera utile lorsque différents éléments de la matrice peuvent être traités en même temps.

Cohérence générale

[modifier | modifier le code]

Dans le cadre de la cohérence générale[13], toutes les copies d'un emplacement mémoire sont finalement identiques une fois que les écritures de tous les processus sont terminées.

Cohérence locale

[modifier | modifier le code]

En cohérence locale[9], chaque processus effectue ses propres opérations dans l'ordre défini par son programme. Il n'y a aucune contrainte sur l'ordre dans lequel les opérations d'écriture des autres processus semblent être effectuées. La cohérence locale est le modèle de cohérence le plus faible dans les systèmes de mémoire partagée.

Autres modèles de cohérence

[modifier | modifier le code]

Voici d'autres modèles de cohérence :

Plusieurs autres modèles de cohérence ont été conçus pour exprimer des restrictions concernant l'ordre ou la visibilité des opérations, ou pour traiter des hypothèses de défaillance spécifiques[16].

Modèles de cohérence de la mémoire relaxée

[modifier | modifier le code]

Certains modèles de cohérence différents peuvent être définis en relâchant une ou plusieurs exigences de la cohérence séquentielle, appelés modèles de cohérence relaxés[17]. Ces modèles de cohérence ne fournissent pas de cohérence mémoire au niveau matériel. En fait, les programmeurs sont responsables de la mise en œuvre de la cohérence de la mémoire en appliquant des techniques de synchronisation. Les modèles ci-dessus sont classés en fonction de quatre critères et sont détaillés plus loin.

Il y a quatre comparaisons pour définir la cohérence relaxée :

Relaxation
Une façon de catégoriser la cohérence relaxée est de définir quelles exigences de cohérence séquentielle sont relaxées. Nous pouvons avoir des modèles moins stricts en relaxant soit l'ordre du programme soit les exigences d'atomicité d'écriture définies par Adve et Gharachorloo, 1996[18]. L'ordre du programme garantit que chaque processus émet une demande de mémoire ordonnée par son programme et l'atomicité d'écriture définit que les demandes de mémoire sont traitées en fonction de l'ordre d'une seule file d'attente FIFO. En relaxant l'ordre du programme, l'ordre des paires d'opérations, écriture après écriture, lecture après écriture, ou lecture/écriture après lecture, peut être relaxé. Dans le modèle d'atomicité d'écriture relaxé, un processus peut voir ses propres écritures avant tout autre processeur.
Synchronisation ou non-synchronisation
Un modèle de synchronisation peut être défini en divisant les accès à la mémoire en deux groupes et en assignant différentes restrictions de cohérence à chaque groupe, en considérant qu'un groupe peut avoir un modèle de cohérence faible tandis que l'autre a besoin d'un modèle de cohérence plus restrictif. En revanche, un modèle de non-synchronisation attribue le même modèle de cohérence aux types d'accès à la mémoire.
Basé sur l'émission ou sur les vues
La méthode d'émission permet de simuler la cohérence séquentielle en définissant les restrictions pour les processus d'émettre des opérations de mémoire. La méthode de vue décrit les restrictions de visibilité sur l'ordre des événements pour les processus[9].
Force relative du modèle
Certains modèles de cohérence sont plus restrictifs que d'autres. En d'autres termes, les modèles de cohérence stricts imposent davantage de contraintes en tant qu'exigences de cohérence. La force d'un modèle peut être définie par l'ordre du programme ou les relaxations d'atomicité et la force des modèles peut également être comparée. Certains modèles sont directement liés s'ils appliquent les mêmes relaxations ou plus. D'autre part, les modèles qui relaxent des exigences différentes ne sont pas directement liés.

La cohérence séquentielle a deux exigences, l'ordre du programme et l'atomicité de l'écriture. Différents modèles de cohérence relaxée peuvent être obtenus en relâchant ces exigences. Le programmeur est toutefois responsable de la mise en œuvre de la cohérence de la mémoire en appliquant des techniques de synchronisation et doit avoir une bonne connaissance du matériel.

Relaxes potentielles :

  • Ordre des programmes d'écriture vers lecture
  • Ordre des programmes d'écriture vers écriture
  • Ordre des programmes de lecture vers lecture

Modèles de relaxation

[modifier | modifier le code]

Les modèles suivants sont quelques modèles de cohérence relaxée :

Relaxe d'écriture vers lecture

[modifier | modifier le code]

Une approche permettant d'améliorer les performances au niveau matériel consiste à relâcher l'OP d'une écriture suivie d'une lecture, ce qui permet de masquer efficacement la latence des opérations d'écriture. L'optimisation sur laquelle repose ce type de relaxation est qu'elle permet aux lectures suivantes d'être dans un ordre détendu par rapport aux écritures précédentes du processeur. À cause de cette relaxation, certains programmes peuvent ne pas donner de résultats SC. D'autres en revanche devraient toujours donner des résultats cohérents en raison de l'application des autres contraintes d'ordre du programme.

Trois modèles entrent dans cette catégorie. Le modèle IBM 370 est le modèle le plus strict. Une lecture peut être terminée avant une écriture antérieure à une adresse différente, mais il lui est interdit de retourner la valeur de l'écriture à moins que tous les processeurs aient vu l'écriture. Le modèle SPARC V8 total store ordering (TSO) assouplit partiellement le modèle IBM 370, il permet à une lecture de renvoyer la valeur de l'écriture de son propre processeur par rapport aux autres écritures au même emplacement, c'est-à-dire qu'elle renvoie la valeur de sa propre écriture avant que les autres ne la voient. Comme le modèle précédent, il ne peut pas renvoyer la valeur de l'écriture si tous les processeurs n'ont pas vu l'écriture. Le modèle de cohérence du processeur (PC) est le plus détendu des trois modèles et relâche les deux contraintes de telle sorte qu'une lecture peut se terminer avant une écriture antérieure, même avant que celle-ci ne soit rendue visible par les autres processeurs.

Dans l'exemple A, le résultat n'est possible que dans l'IBM 370 parce que la lecture (A) n'est pas émise avant que l'écriture (A) dans ce processeur soit terminée. Par contre, ce résultat est possible dans TSO et PC car ils permettent la lecture des drapeaux avant l'écriture des drapeaux dans un seul processeur.

Dans l'exemple B, le résultat n'est possible qu'avec le PC car il permet à P2 de renvoyer la valeur d'une écriture avant même qu'elle ne soit visible par P3. Cela ne sera pas possible dans les deux autres modèles.

Pour assurer la cohérence séquentielle dans les modèles ci-dessus, des filets de sécurité ou des barrières sont utilisés pour faire respecter manuellement la contrainte. Le modèle IBM370 comporte certaines instructions de sérialisation spécialisées qui sont placées manuellement entre les opérations. Ces instructions peuvent être des instructions mémoire ou des instructions non mémoire telles que des branches. D'autre part, les modèles TSO et PC ne fournissent pas de filets de sécurité, mais les programmeurs peuvent toujours utiliser des opérations de lecture-modification-écriture pour faire croire que l'ordre du programme est toujours maintenu entre une écriture et une lecture suivante. Dans le cas de TSO, le PO semble être maintenu si le R ou le W qui fait déjà partie d'un R-modify-W est remplacé par un R-modify-W, ce qui nécessite que le W dans le R-modify-W soit un 'factice' qui renvoie la valeur lue. De même, pour PC, PO semble être maintenu si la lecture est remplacée par une écriture ou fait déjà partie de R-modifié-W.

Cependant, les optimisations du compilateur ne peuvent pas être effectuées après avoir exercé cette seule relaxation. Les optimisations du compilateur requièrent la flexibilité totale de pouvoir réordonner n'importe quelles des deux opérations dans l'OP, donc la possibilité de réordonner une écriture par rapport à une lecture n'est pas suffisamment utile dans ce cas.

Exemple A
P1 P2
A = flag1 = flag2 = 0
flag1 = 1 flag2 = 1
A = 1 A = 2
reg1 = A reg3 = A
reg2 = flag2 reg4 = flag1
reg1 = 1; reg3 = 2, reg2 = reg4 = 0
Exemple B
P1 P2 P3
A = B = 0
A = 1
if (A == 1)
B = 1 if (B == 1)
reg1 = A
B = 1, reg1 = 0

Relaxe d'écriture vers lecture et d'écriture vers écriture

[modifier | modifier le code]

Certains modèles relaxent encore plus l'ordre du programme en relaxant même les contraintes d'ordre entre les écritures à différents emplacements. Le modèle PSO (partial store ordering) de SPARC V8 est le seul exemple d'un tel modèle. La capacité de canaliser et de chevaucher les écritures à différents emplacements à partir du même processeur est la principale optimisation matérielle permise par PSO. PSO est similaire à TSO en termes d'exigences d'atomicité, en ce sens qu'il permet à un processeur de lire la valeur de sa propre écriture et empêche les autres processeurs de lire l'écriture d'un autre processeur avant que l'écriture ne soit visible par tous les autres processeurs. L'ordre du programme entre deux écritures est maintenu par PSO en utilisant une instruction STBAR explicite. L'instruction STBAR est insérée dans un tampon d'écriture dans les implémentations avec des tampons d'écriture FIFO. Un compteur est utilisé pour déterminer quand toutes les écritures avant l'instruction STBAR ont été effectuées, ce qui déclenche une écriture dans le système de mémoire pour incrémenter le compteur. Un accusé de réception d'écriture décrémente le compteur, et lorsque le compteur devient 0, cela signifie que toutes les écritures précédentes sont terminées.

Dans les exemples A et B, PSO permet ces deux résultats non séquentiellement cohérents. Le filet de sécurité que fournit PSO est similaire à celui de TSO, il impose l'ordre du programme d'une écriture vers une lecture et fait respecter l'atomicité de l'écriture.

Comme pour les modèles précédents, les relaxations permises par PSO ne sont pas suffisamment flexibles pour être utiles à l'optimisation des compilateurs, qui nécessite une optimisation beaucoup plus souple.

Relaxation des commandes de programmes de lecture et de lecture vers écriture

[modifier | modifier le code]

Dans certains modèles, toutes les opérations sur des emplacements différents sont relaxées. Une lecture ou une écriture peut être réordonnée par rapport à une autre lecture ou écriture dans un autre emplacement. L'ordonnancement faible peut être classé dans cette catégorie et deux types de modèles de cohérence de libération (RCsc et RCpc) relèvent également de ce modèle. Trois architectures commerciales sont également proposées dans cette catégorie de relaxation : les modèles Digital Alpha, SPARC V9 relaxed memory order (RMO) et IBM PowerPC. Tous ces modèles permettent de réordonner les lectures au même emplacement, sauf le Digital Alpha. Ces modèles violent l'ordre séquentiel dans les exemples A et B. Une relaxation supplémentaire autorisée dans ces modèles, absente des modèles précédents, est que les opérations de mémoire suivant une opération de lecture peuvent être superposées et réordonnées par rapport à la lecture. Tous ces modèles, à l'exception du RCpc et du PowerPC, permettent à une lecture de retourner la valeur de l'écriture précoce d'un autre processeur. Du point de vue du programmeur, tous ces modèles doivent maintenir l'illusion de l'atomicité de l'écriture même s'ils permettent au processeur de lire sa propre écriture en avance.

Ces modèles peuvent être classés en deux catégories en fonction du type de filet de sécurité fourni. On voit ici la nécessité de programmes soigneusement écrits. La nature de la synchronisation aide à catégoriser les modèles d'ordre faible, RCsc et RCpc. Les modèles Alpha, RMO et PowerPC fournissent des instructions de clôture afin que l'ordre du programme puisse être imposé entre différentes opérations de mémoire.

Ordonnancement faible

[modifier | modifier le code]

Un exemple de modèle qui relâche la plupart des contraintes ci-dessus (à l'exception de la lecture anticipée de l'écriture d'autrui) est l'ordonnancement faible. Il classe les opérations de mémoire en deux catégories : les opérations de données et les opérations de synchronisation. Pour faire respecter l'ordre du programme, un programmeur doit trouver au moins une opération de synchronisation dans un programme. L'hypothèse selon laquelle cela fonctionne est que la réorganisation des opérations de mémoire dans les régions de données entre les opérations de synchronisation n'affecte pas le résultat du programme. Elles agissent simplement comme un filet de sécurité pour faire respecter l'ordre du programme. La façon dont cela fonctionne est qu'un compteur suit le nombre d'opérations de données et tant que ce compteur ne devient pas nul, l'opération de synchronisation n'est pas émise. De plus, aucune autre opération de données n'est émise tant que toutes les synchronisations précédentes ne sont pas terminées. Les opérations de mémoire entre deux variables de synchronisation peuvent être superposées et réordonnées sans affecter la correction du programme. Ce modèle garantit que l'atomicité de l'écriture est toujours maintenue, par conséquent, aucun filet de sécurité supplémentaire n'est nécessaire pour l'ordonnancement faible.

Cohérence de validation : RCsc et RCpc

[modifier | modifier le code]

Il existe deux types de cohérence de validation, la cohérence de validation avec la cohérence séquentielle (RCsc) et la cohérence de validation avec la cohérence du processeur (RCpc). Ce dernier type indique quel type de cohérence est appliqué aux opérations désignées ci-dessous comme spéciales.

Il existe des opérations mémoire spéciales (cf. ordinaires), elles-mêmes composées de deux classes d'opérations : les opérations sync ou nsync. Ces dernières sont des opérations qui ne sont pas utilisées pour la synchronisation ; les premières le sont, et consistent en des opérations d'acquisition et de libération. Une acquisition est effectivement une opération de lecture de la mémoire utilisée pour obtenir l'accès à un certain ensemble d'emplacements partagés. La libération, quant à elle, est une opération d'écriture effectuée pour accorder la permission d'accéder aux emplacements partagés.

Pour la cohérence séquentielle (RCsc), les contraintes sont :

  • acquérir → tous,
  • tous → validation,
  • spécial → spécial.

Pour la cohérence du processeur (RCpc), l'ordre des programmes d'écriture et de lecture est relâché, avec des contraintes :

  • acquérir → tous,
  • tous → validation,
  • spécial → spécial (sauf lorsque l'écriture spéciale est suivie d'une lecture spéciale).

Remarque : la notation ci-dessus A → B, implique que si l'opération A précède B dans l'ordre du programme, alors l'ordre du programme est respecté.

Alpha, RMO, and PowerPC

[modifier | modifier le code]

Ces trois architectures commerciales présentent des instructions de clôture explicites comme leurs filets de sécurité. Le modèle Alpha fournit deux types d'instructions de clôture, la barrière mémoire (MB) et la barrière mémoire en écriture (WMB). L'opération MB peut être utilisée pour maintenir l'ordre du programme de toute opération mémoire avant la MB avec une opération mémoire après la barrière. De même, la WMB maintient l'ordre du programme uniquement entre les écritures. Le modèle RMO SPARC V9 fournit une instruction MEMBAR qui peut être personnalisée pour ordonner les lectures et écritures précédentes par rapport aux opérations de lecture et d'écriture futures. Il n'est pas nécessaire d'utiliser des lectures-modifications-écritures pour obtenir cet ordre car l'instruction MEMBAR peut être utilisée pour ordonner une écriture par rapport à une lecture suivante. Le modèle PowerPC utilise une seule instruction de clôture appelée instruction SYNC. Elle est similaire à l'instruction MB, mais à la petite exception que les lectures peuvent se produire hors de l'ordre du programme même si un SYNC est placé entre deux lectures au même endroit. Ce modèle diffère également d'Alpha et de RMO en termes d'atomicité. Il permet à une écriture d'être vue avant l'achèvement d'une lecture. Une combinaison d'opérations d'écriture modifiant la lecture peut être nécessaire pour donner l'illusion de l'atomicité de l'écriture.

Modèles de mémoire transactionnelle

[modifier | modifier le code]

Le modèle de mémoire transactionnelle[17] est la combinaison des modèles de cohérence du cache et de cohérence de la mémoire en tant que modèle de communication pour les systèmes de mémoire partagée supportés par le logiciel ou le matériel ; un modèle de mémoire transactionnelle fournit à la fois la cohérence de la mémoire et la cohérence du cache. Une transaction est une séquence d'opérations exécutée par un processus qui transforme les données d'un état cohérent à un autre. Une transaction est soit validée lorsqu'il n'y a pas de conflit, soit abandonnée. Dans le cas d'un commit, toutes les modifications sont visibles pour tous les autres processus lorsque la transaction est terminée, tandis que dans le cas d'un abandon, toutes les modifications sont supprimées. Par rapport aux modèles de cohérence relaxés, un modèle transactionnel est plus facile à utiliser et peut fournir des performances plus élevées qu'un modèle de cohérence séquentiel.

Cohérence et réplication

[modifier | modifier le code]

Tanenbaum et al., 2007[19] définit deux raisons principales pour la réplication : la fiabilité et les performances. La fiabilité peut être obtenue dans un système de fichiers répliqué en passant à une autre réplique en cas de défaillance de la réplique actuelle. La réplication protège également les données contre la corruption en fournissant plusieurs copies des données sur différentes répliques. Elle améliore également les performances en divisant le travail. Bien que la réplication puisse améliorer les performances et la fiabilité, elle peut causer des problèmes de cohérence entre les copies multiples de données. Les copies multiples sont cohérentes si une opération de lecture renvoie la même valeur de toutes les copies et si une opération d'écriture, en tant qu'opération atomique unique (transaction), met à jour toutes les copies avant toute autre opération. Tanenbaum, Andrew et Maarten Van Steen (2007) [19]qualifient ce type de cohérence de cohérence stricte fournie par la réplication synchrone. Cependant, l'application de synchronisations globales pour maintenir la cohérence de toutes les copies est coûteuse. Une façon de diminuer le coût de la synchronisation globale et d'améliorer les performances peut être d'affaiblir les restrictions de cohérence.

Modèles de cohérence centrés sur les données

[modifier | modifier le code]

Tanenbaum et al., 2007[19] définit le modèle de cohérence comme un contrat entre le logiciel (processus) et l'implémentation de la mémoire (magasin de données). Ce modèle garantit que si le logiciel suit certaines règles, la mémoire fonctionne correctement. Puisque, dans un système sans horloge globale, il est difficile de définir la dernière opération parmi les écritures, certaines restrictions peuvent être appliquées sur les valeurs qui peuvent être retournées par une opération de lecture.

Ordre cohérent des opérations

[modifier | modifier le code]

Certains modèles de cohérence, tels que les modèles de cohérence séquentielle ou causale, traitent de l'ordre des opérations sur les données répliquées partagées afin d'assurer la cohérence. Dans ces modèles, toutes les répliques doivent convenir d'un ordre global cohérent des mises à jour.

Cohérence séquentielle
[modifier | modifier le code]

L'objectif des modèles de cohérence centrés sur les données est de fournir une vue cohérente sur un magasin de données où les processus peuvent effectuer des mises à jour simultanées. Un important modèle de cohérence centré sur les données est la cohérence séquentielle définie par Lamport (1979)[4]. Tanenbaum et al., 2007[19] définit la cohérence séquentielle sous la condition suivante :

Le résultat de toute exécution est le même que si les opérations (lecture et écriture) effectuées par tous les processus sur le magasin de données étaient exécutées dans un certain ordre séquentiel et que les opérations de chaque processus individuel apparaissaient dans cette séquence dans l'ordre spécifié par son programme[19].

Adve et Gharachorloo, 1996[18] définissent deux exigences pour mettre en œuvre la cohérence séquentielle : l'ordre du programme et l'atomicité de l'écriture.

  • Ordre des programmes : L'ordre des programmes garantit que chaque processus émet une demande de mémoire ordonnée par son programme.
  • Atomicité d'écriture : L'atomicité d'écriture définit le fait que les demandes de mémoire sont traitées en fonction de l'ordre d'une seule file d'attente FIFO.

Dans la cohérence séquentielle, il n'y a pas de notion de temps ou d'opérations d'écriture les plus récentes. Il y a un entrelacement des opérations qui est le même pour tous les processus. Un processus peut voir les opérations d'écriture de tous les processus mais il ne peut voir que ses propres opérations de lecture.

La linéarisabilité[20] (mémoire atomique)[17] peut être définie comme une cohérence séquentielle avec une contrainte de temps réel en considérant un temps de début et un temps de fin pour chaque opération. Une exécution est linéarisable si chaque opération se déroule dans un ordre linéarisable en plaçant un point entre son heure de début et son heure de fin et garantit la cohérence séquentielle.

Cohérence causale
[modifier | modifier le code]

La cohérence causale[19] définie par Hutto et Ahamad, 1990[10] est un modèle de cohérence plus faible que la cohérence séquentielle en faisant la distinction entre les opérations causalement liées et celles qui ne le sont pas. Par exemple, si un événement b prend effet à partir d'un événement a antérieur, la cohérence causale garantit que tous les processus voient l'événement b après l'événement a.

Tanenbaum et al., 2007[19] définit qu'un magasin de données est considéré comme cohérent du point de vue causal dans la condition suivante :

Les écritures qui sont potentiellement liées de manière causale doivent être vues par tous les processus dans le même ordre. Les écritures concurrentes peuvent être vues dans un ordre différent sur différentes machines[19].

Cohérence éventuelle

[modifier | modifier le code]

Une cohérence éventuelle[19] est un modèle de cohérence faible dans le système avec l'absence de mises à jour simultanées. Il définit que si aucune mise à jour ne prend un temps très long, toutes les répliques finissent par devenir cohérentes.

La plupart des bases de données décentralisées partagées ont un modèle de cohérence éventuelle, soit BASE : fondamentalement disponible ; état mou ; éventuellement cohérent, soit une combinaison d'ACID et de BASE parfois appelée SALT : séquentielle ; convenue ; jalonnée ; inviolable, et également symétrique ; sans administration ; jalonnée ; et consensuelle dans le temps[21],[22],[23].

Cohérence éventuelle forte

[modifier | modifier le code]

La cohérence éventuelle forte (Strong Eventual Consistency, SEC) représente une extension du modèle de cohérence éventuelle, introduisant la garantie que les répliques convergent vers un état commun, quel que soit l'ordre des mises à jour. Autrement dit, toutes les répliques ayant observé les mêmes mises à jour atteindront un état équivalent. Par conséquent, les répliques peuvent être mis à jour simultanément et les mises à jour concurrentes seront résolues sans synchronisation.[24]

Les types de données répliqués sans conflit reposent sur ce modèle de cohérence.

Opérations de regroupement
[modifier | modifier le code]

En opération de regroupement, les accès aux variables de synchronisation sont séquentiellement cohérents. Un processus est autorisé à accéder à une variable de synchronisation que toutes les écritures précédentes ont été complétées. En d'autres termes, les accès aux variables de synchronisation ne sont pas autorisés tant que toutes les opérations sur les variables de synchronisation ne sont pas complètement effectuées[19].

Cohérence continue

[modifier | modifier le code]

La cohérence continue est définie plus loin dans la section sur le protocole de cohérence.

Modèles de cohérence centrés sur le client

[modifier | modifier le code]

Dans les systèmes distribués, il est essentiel de maintenir la cohérence séquentielle afin de contrôler les opérations simultanées. Dans certains magasins de données spéciaux sans mises à jour simultanées, les modèles de cohérence centrés sur le client peuvent traiter les incohérences d'une manière moins coûteuse. Les modèles suivants sont des modèles de cohérence centrés sur le client[19] :

Cohérence monotone de la lecture

[modifier | modifier le code]

Tanenbaum et al., 2007[19] définit la cohérence monotone de la lecture comme suit :

"Si un processus lit la valeur d'une donnée x, toute opération de lecture successive sur x par ce processus retournera toujours cette même valeur ou une valeur plus récente."[19]

La cohérence monotone de la lecture garantit qu'après qu'un processus a lu une valeur de l'élément de données x à l'instant t, il ne verra jamais l'ancienne valeur de cet élément de données.

Cohérence d'écriture monotone

[modifier | modifier le code]

La condition de cohérence d'écriture monotone est définie par Tanenbaum et al., 2007[19] comme suit :

"Une opération d'écriture par un processus sur une donnée X est terminée avant toute opération d'écriture successive sur X par le même processus."[19]

Cohérence de la lecture des écrits

[modifier | modifier le code]

Une valeur écrite par un processus sur un élément de données X sera toujours disponible pour une opération de lecture successive effectuée par le même processus sur l'élément de données X[19].

Cohérence écriture-lecture

[modifier | modifier le code]

Dans le cas de la cohérence écriture-lecture, les mises à jour sont propagées après l'exécution des opérations de lecture précédentes. Tanenbaum et al., 2007[19] définit la condition suivante pour la cohérence écriture-lecture :

"Une opération d'écriture par un processus sur une donnée x à la suite d'une opération de lecture précédente sur x par le même processus est garantie d'avoir lieu sur la même valeur ou une valeur plus récente de x qui a été lue."[19]

Protocoles de cohérence

[modifier | modifier le code]

La mise en œuvre d'un modèle de cohérence est définie par un protocole de cohérence. Tanenbaum et al., 2007[19] illustre certains protocoles de cohérence pour les modèles centrés sur les données.

Cohérence continue

[modifier | modifier le code]

La cohérence continue a été introduite par Yu et Vahdat (2000)[25]. Dans ce modèle, la sémantique de cohérence d'une application est décrite en utilisant des unités de cohérence dans l'application. Étant donné que les exigences en matière de cohérence peuvent différer en fonction de la sémantique de l'application, Yu et Vahdat (2000) estiment qu'un modèle de cohérence uniforme prédéfini n'est peut-être pas une approche appropriée. L'application doit spécifier les exigences de cohérence qui satisfont la sémantique de l'application. Dans ce modèle, une application spécifie chaque exigence de cohérence sous forme d'unités de cohérence. Une unité de cohérence peut être une cohérence physique ou logique et est utilisée pour mesurer la cohérence. Tanenbaum et al, 2007[19] décrit la notion d'unité de cohérence en donnant un exemple.

Il existe trois incohérences qui peuvent être tolérées par les applications.

Écart dans les valeurs numériques
L'écart numérique limite la différence entre la valeur de l'unité de cohérence et la valeur relative de la dernière mise à jour. Un poids peut être attribué aux écritures, ce qui définit l'importance des écritures dans une application spécifique. Le poids total des écritures non vues pour une unité de cohérence peut être défini comme un écart numérique dans une application. Il existe deux types d'écart numérique : l'écart numérique absolu et l'écart numérique relatif[25].
Écart dans la commande
L'écart d'ordonnancement est la divergence entre l'ordre local des écritures dans une réplique et leur ordre relatif dans l'image finale éventuelle[25].
Écart de vétusté entre les répliques
L'écart de vétusté définit la validité de l'écriture la plus ancienne en bornant la différence entre l'heure actuelle et l'heure de l'écriture la plus ancienne sur une unité de cohérence non vue localement. Chaque serveur a une file d'attente locale d'écritures incertaines qui sont nécessaires pour qu'un ordre réel soit déterminé et appliqué sur une unité de cohérence. La longueur maximale de la file d'attente des écritures incertaines est la limite de la déviation de l'ordre. Lorsque le nombre d'écritures dépasse la limite, au lieu d'accepter de nouvelles écritures soumises, le serveur tentera de valider les écritures incertaines en communiquant avec d'autres serveurs en fonction de l'ordre dans lequel les écritures doivent être exécutées[25].

Si les trois limites d'écart sont fixées à zéro, le modèle de cohérence continue est la cohérence forte.

Protocoles primaires

[modifier | modifier le code]
Protocole de sauvegarde primaire
Protocole de sauvegarde primaire (écriture locale)

Les protocoles basés sur les primaires[19] peuvent être considérés comme une classe de protocoles de cohérence plus simples à mettre en œuvre. Par exemple, l'ordonnancement séquentiel est un modèle de cohérence populaire lorsque l'on considère l'ordonnancement cohérent des opérations. L'ordonnancement séquentiel peut être déterminé comme un protocole basé sur les primaires. Dans ces protocoles, il y a un primaire associé à chaque élément de données dans un magasin de données pour coordonner les opérations d'écriture sur cet élément de données.

Protocoles d'écriture à distance
[modifier | modifier le code]

Dans le protocole le plus simple basé sur le primaire et prenant en charge la réplication, également appelé protocole primaire de sauvegarde, les opérations d'écriture sont transmises à un seul serveur et les opérations de lecture peuvent être effectuées localement.

Exemple : Tanenbaum et al., 2007[19] donne un exemple de protocole de sauvegarde primaire. Le diagramme du protocole de sauvegarde primaire montre un exemple de ce protocole. Lorsqu'un client demande une écriture, la demande d'écriture est transmise à un serveur primaire. Le serveur primaire envoie une demande aux sauvegardes pour effectuer la mise à jour. Le serveur reçoit ensuite l'accusé de réception de la mise à jour de toutes les sauvegardes et envoie l'accusé de réception de l'achèvement des écritures au client. Tout client peut lire localement la dernière mise à jour disponible. La contrepartie de ce protocole est qu'un client qui envoie une demande de mise à jour peut devoir attendre longtemps avant de recevoir l'accusé de réception pour pouvoir continuer. Ce problème peut être résolu en effectuant les mises à jour localement, puis en demandant aux autres sauvegardes d'effectuer leurs mises à jour. Le protocole de sauvegarde primaire non bloquant ne garantit pas la cohérence des mises à jour sur tous les serveurs de sauvegarde. Cependant, il améliore les performances. Dans le protocole de sauvegarde primaire, tous les processus verront le même ordre d'opérations d'écriture puisque ce protocole ordonne toutes les écritures entrantes sur la base d'un temps unique au niveau mondial. Les protocoles de blocage garantissent que les processus voient le résultat de la dernière opération d'écriture.
Protocoles d'écriture locale
[modifier | modifier le code]

Dans les protocoles d'écriture locale basés sur le primaire[19], la copie primaire se déplace entre les processus désireux d'effectuer une mise à jour. Pour mettre à jour un élément de données, un processus le déplace d'abord à son emplacement. Par conséquent, dans cette approche, les opérations d'écriture successives peuvent être effectuées localement tandis que chaque processus peut lire sa copie locale des éléments de données. Une fois que le primaire a terminé sa mise à jour, celle-ci est transmise aux autres répliques et toutes effectuent la mise à jour localement. Cette approche non bloquante peut conduire à une amélioration. Le diagramme du protocole local d'écriture décrit l'approche locale d'écriture dans les protocoles basés sur les primaires. Un processus demande une opération d'écriture dans un élément de données x. Le serveur actuel est considéré comme le nouveau primaire pour un élément de données x. L'opération d'écriture est effectuée et lorsque la demande est terminée, le primaire envoie une demande de mise à jour aux autres serveurs de sauvegarde. Chaque sauvegarde envoie un accusé de réception au primaire après avoir terminé l'opération de mise à jour.

Protocoles de copie écrite

[modifier | modifier le code]

Dans les protocoles de copie écrite[19], contrairement au protocole basé sur le primaire, toutes les mises à jour sont effectuées sur toutes les copies.

Reproduction active
[modifier | modifier le code]

Dans la reproduction active[19], il y a un processus associé à chaque réplique pour effectuer l'opération d'écriture. En d'autres termes, les mises à jour sont envoyées à chaque réplique sous la forme d'une opération afin d'être exécutées. Toutes les mises à jour doivent être exécutées dans le même ordre dans toutes les répliques. Par conséquent, un mécanisme de multidiffusion totalement ordonné est nécessaire. La mise en œuvre d'un tel mécanisme de multidiffusion dans les grands systèmes distribués pose un problème d'évolutivité. Il existe une autre approche dans laquelle chaque opération est envoyée à un coordinateur central (séquenceur). Le coordinateur attribue d'abord un numéro de séquence à chaque opération, puis transmet l'opération à toutes les répliques. Cette deuxième approche ne peut pas non plus résoudre le problème d'évolutivité.

Protocoles basés sur le quorum
[modifier | modifier le code]

Le vote peut être une autre approche dans les protocoles de copie écrite. Dans cette approche, un client demande et reçoit la permission de plusieurs serveurs afin de lire et d'écrire des données répliquées. Par exemple, supposons que dans un système de fichiers distribué, un fichier est répliqué sur N serveurs. Pour mettre à jour un fichier, un client doit envoyer une demande à au moins N/2 + 1 afin d'obtenir leur accord pour effectuer une mise à jour. Après l'accord, les modifications sont appliquées sur le fichier et un nouveau numéro de version est attribué au fichier mis à jour. De même, pour lire un fichier répliqué, un client envoie une demande à N/2 + 1 serveurs afin de recevoir le numéro de version associé de ces serveurs. L'opération de lecture est terminée si tous les numéros de version reçus sont la version la plus récente[19].

Protocoles de cohérence des caches
[modifier | modifier le code]

Dans un système de fichiers répliqué, un protocole de cohérence du cache[19] assure la cohérence du cache tandis que les caches sont généralement contrôlés par les clients. Dans de nombreuses approches, la cohérence du cache est assurée par le matériel sous-jacent. D'autres approches dans les systèmes distribués basés sur des intergiciels appliquent des solutions logicielles pour assurer la cohérence du cache.

Les modèles de cohérence des caches peuvent différer par leurs stratégies de détection de la cohérence qui définissent quand les incohérences se produisent. Il existe deux approches pour détecter l'incohérence : les solutions statiques et dynamiques. Dans la solution statique, un compilateur détermine quelles variables peuvent causer l'incohérence du cache. Ainsi, le compilateur impose une instruction afin d'éviter le problème d'incohérence. Dans la solution dynamique, le serveur vérifie les incohérences au moment de l'exécution pour contrôler la cohérence des données mises en cache qui ont changé après leur mise en cache.

La stratégie d'application de la cohérence est un autre protocole de cohérence du cache. Elle définit comment assurer la cohérence des caches en utilisant les copies situées sur le serveur. Une façon de maintenir la cohérence des données est de ne jamais mettre en cache les données partagées. Un serveur peut conserver les données et appliquer un protocole de cohérence tel que les protocoles basés sur les primaires pour assurer la cohérence des données partagées. Dans cette solution, seules les données privées peuvent être mises en cache par les clients. Dans le cas où les données partagées sont mises en cache, il existe deux approches pour faire respecter la cohérence du cache.

Dans la première approche, lorsqu'une donnée partagée est mise à jour, le serveur transmet l'invalidation à tous les caches. Dans la deuxième approche, une mise à jour est propagée. La plupart des systèmes de mise en cache appliquent ces deux approches ou choisissent dynamiquement entre elles.

Références

[modifier | modifier le code]
  1. (en) Mark D. Hill, « Multiprocessors Should Support Simple Memory Consistency Models », IEEE Computer, vol. 31, no 8,‎ , p. 28-34 (DOI 10.1109/2.707614, lire en ligne)
  2. (en) Shaz Qadeer, « Verifying Sequential Consistency on Shared-Memory Multiprocessors by Model Checking », IEEE Transactions on Parallel and Distributed Systems, vol. 14, no 8,‎ aoput 2003, p. 730-741 (DOI 10.1109/TPDS.2003.1225053, arXiv cs/0108016)
  3. a et b Todd Lipcon, « Design Patterns for Distributed Non-Relational Databases » [PDF], (consulté le ) : « Un modèle de cohérence détermine les règles de visibilité et l'ordre apparent des mises à jour. Exemple : * La ligne X est répliquée sur les noeuds M et N * Le client A écrit la ligne X sur le noeud N * Une période de temps t s'écoule. * Le client B lit la ligne X depuis le noeud M. Le client B voit-il l'écriture du client A ? La cohérence est un continuum avec des compromis. »
  4. a et b (en) Lamport, Leslie, « How to make a multiprocessor computer that correctly executes multiprocess programs. », IEEE Transactions on Computers, vol. C-28, no 9,‎ , p. 690-691 (DOI 10.1109/TC.1979.1675439)
  5. a b et c (en) « Memory Consistency Models »
  6. a et b James R Goodman, « Cache consistency and sequential consistency », IEEE Scalable Coherent Interface (SCI) Working Group,‎
  7. a et b .(en) Maximilian Senftleben, Operational Characterization of Weak Memory Consistency Models (Mémoire de maîtrise), University of Kaiserslautern, , 81 p. (lire en ligne)
  8. (en) R.J. Lipton et J.S. Sandberg, PRAM: A scalable shared memory, Princeton University,
  9. a b c et d (en) Robert C. Steinke et Gary J. Nutt, « A unified theory of shared memory consistency. », Journal of the ACM, vol. 51, no 5,‎ , p. 800-849 (DOI 10.1145/1017460.1017464, arXiv cs/0208027)
  10. a et b (en) Phillip W. Hutto et Ahamad Mustaque, Slow memory: Weakening consistency to enhance concurrency in distributed shared memories., IEEE, (ISBN 978-0-8186-2048-5, DOI 10.1109/ICDCS.1990.89297), p. 302-309
  11. (en) Sarita V Adve et Kourosh Gharachorloo, « Shared Memory Consistency Models : A tutorial » [PDF], sur hp.com, (consulté le )
  12. Yan Solihin, Fundamentals of Parallel Computer Architecture, Solihin Books,
  13. (en) Singhal Mukesh et Niranjan G. Shivaratri, « Advanced concepts in operating systems. », McGraw-Hill, Inc,‎ (lire en ligne Inscription nécessaire)
  14. (en) Wyatt Lloyd, Michael J. Freedman, Michael Kaminsky et David G. Andersen, « Don’t Settle for Eventual: Scalable Causal Consistency for Wide-Area Storage with COPS » [PDF] (consulté le )
  15. (en) Sérgio Almeida, João Leitão et Luís Rodrigues, ChainReaction: a causal+ consistent datastore based on chain replication, , 85 p. (ISBN 978-1-450-31994-2, DOI 10.1145/2465351.2465361), « Chain Reaction »
  16. (en) Paolo Viotti et Marko Vukolic, « Consistency in Non-Transactional Distributed Storage Systems », ACM Computing Surveys, vol. 49, no 1,‎ , p. 19:1–19:34 (DOI 10.1145/2926965, arXiv 1512.00168)
  17. a b et c (en) Jenny Mankin, CSG280: Parallel Computing Memory Consistency Models: A Survey in Past and Present Research, (lire en ligne)
  18. a et b (en) Sarita V. Adve et Kourosh Gharachorloo, « Shared Memory Consistency Models: A Tutorial », IEEE Computer, vol. 29, no 12,‎ , p. 66-76 (DOI 10.1109/2.546611, lire en ligne [PDF], consulté le )
  19. a b c d e f g h i j k l m n o p q r s t u v w x y z et aa (en) Tanenbaum, Andrew et Maarten Van Steen, « Distributed systems », Pearson Prentice Hall,‎
  20. (en) Herlihy, Maurice P. et Jeannette M. Wing, « "Linearizability: A correctness condition for concurrent objects." ACM Transactions on Programming Languages and Systems », ACM Transactions on Programming Languages and Systems, vol. 12, no 3,‎ , p. 463-492 (DOI 10.1145/78969.78972)
  21. (en) Collin Cusce. "SALT: A Descriptive Model For Blockchain". 2018.
  22. (en) Stefan Tai, Jacob Eberhardt, and Markus Klems. "Not ACID, not BASE, but SALT: A Transaction Processing Perspective on Blockchains".
  23. (en) Chao Xie, Chunzhi Su, Manos Kapritsos, Yang Wang, Navid Yaghmazadeh, Lorenzo Alvisi, Prince Mahajan. "Salt: Combining ACID and BASE in a Distributed Database".
  24. (en) Marc Shapiro, Nuno Preguiça, Carlos Baquero et Marek Zawirski, « Conflict-free Replicated Data Types », INRIA,‎ (ISSN 0249-6399, HAL hal-00609399v1, lire en ligne [PDF], consulté le )
  25. a b c et d (en) Yu, Haifeng et Amin Vahdat, « Design and evaluation of a continuous consistency model for replicated services. », Proceedings of the 4th Conference on Symposium on Operating System Design & Implementation, vol. 4,‎ , p. 21

En savoir plus

[modifier | modifier le code]
  • (en) Paolo Viotti et Marko Vukolic, « Consistency in Non-Transactional Distributed Storage Systems », ACM Computing Surveys, vol. 49, no 1,‎ , p. 19:1–19:34 (DOI 10.1145/2926965, arXiv 1512.00168)
  • (en) Ali Sezgin, Formalization and verification of shared memory, (lire en ligne)
  • (en) Kathy Yelick, Dan Bonachea et Chuck Wallace, A Proposal for a UPC Memory Consistency Model (v1.0),
  • (en) Mosberger, David, « Memory Consistency Models », Operating Systems Review, vol. 27, no 1,‎ , p. 18-26 (DOI 10.1145/160551.160553, lire en ligne Inscription nécessaire)
  • (en) Sarita V. Adve et Kourosh Gharachorloo, « Shared Memory Consistency Models: A Tutorial », IEEE Computing, vol. 29, no 12,‎ , p. 66-76 (DOI 10.1109/2.546611, lire en ligne [PDF], consulté le )
  • (en) Steinke, Robert C et Gary J. Nutt, « A unified theory of shared memory consistency », Journal of the ACM, vol. 51, no 5,‎ , p. 800-849 (DOI 10.1145/1017460.1017464, arXiv cs.DC/0208027)

Liens externes

[modifier | modifier le code]