Bordeau Oceane, Gharbi Wassim, Scheidler Nicolas, Schneider Martin
Notre projet permet d'accèder à un document texte en lecture/écriture depuis plusieurs sites de manière simultanée. L'édition de ce document correspond à la section critique du programme. La communication des sites est assurée par le biais d'un anneau. Pour répondre à nos objectifs, un algortihme réparti a été implémenté. Celui-ci est composé de plusieurs algortihmes fondamentaux :
- Un algorithme de file d'attente : pour coordonner les demandes d'entrée en section critique entre les différents sites ;
- Un algorithme de sauvegarde : pour capturer un instantané cohérent de l'état de l'éxécution (document, demandes en attente, traffic réseau).
Une interface web est également accessible.
Tout d'abord, il est necessaire d'importer le projet sur votre machine.
Vous pouvez cloner le repo Github :
$ git clone https://github.com/martinschnder/projet_sr05.gitou décompresser l'archive tar.
Voici l'arborescence que vous devriez avoir :
Compilez le projet à sa racine pour obtenir un executable avec la commande suivante :
$ go buildUn éxécutable "projet" devrait apparaître.
Exécuter le script startup.sh :
$ ./startup.shIl execute une instance du projet par site et les met en réseau en anneau grâce à la commande :
./projet -id 0 -port 2222 < /tmp/f | ./projet -id 1 -port 3333 | ./projet -id 2 -port 4444 > /tmp/fIci, nous créons 3 sites distincts sur 3 ports : 2222, 3333, 4444.
Ouvrir les interfaces web avec autant de pages que de sites (3 ici) :
$ firefox client/client.htmlSur chaque interface, connectez les websockets (sur les ports 2222, 3333, 4444).
Une fois la websocket connectée, vous devriez obtenir des logs semblables sur l'interface :
Avec le visuel du document, vous pouvez suivre son état. Depuis chaque site, vous pouvez éditer le document :
- Ligne : Selectionner le numéro de la ligne que vous souhaitez modifier ;
- Action : Choisisser ce que vous voulez faire sur cette ligne (Remplacer, Ajouter ou Supprimer), ajouter permet d'ajouter à une ligne du texte ;
- Texte : Entrer le texte que vous voulez.
Vous pouvez vérifier qu'une action sur un site entraîne la modification de chaque réplicats sur tous les sites.
Enfin vous pouvez réaliser un snapshot. Le clic sur le bouton "Faire un snapshot" génére un fichier "snapshot.txt".
Dès lors que le client souhaite envoyer un message à son serveur, il construit une commande au format /=line=.../=action=.../=message=... et l'envoi à travers la websocket.
Lorsque le serveur souhaite envoyer un message à son client, il construit un objet JSON comprenant le texte du document et l'horloge.
Les différents sites sont connectés au travers d'un anneau, lorsqu'un site souhaite communiquer avec les autres, il envoie sur son canal stdout un message au format |=From=...|=To=...|=Content=...|=Stamp=...|=MessageType=...|=VectClock=...|=Color=...
Sur chaque site une goroutine ReadMessage s'occupe de lire ce qui arrive sur le canal stdin et la passe dans un canal de communication messages propre au site. La goroutine MessageHandler s'occupe de lire ce qui arrive sur ce canal de communication et de le traiter (en fonction de s'il lui est destiné ou non).
Si un site souhaite envoyer un message à un autre site, alors il utilise la fonction writeMessage qui écrira dans le canal de communication messages pour que MessageHandler le propage aux autres sites.
Le code a été écrit en se basant sur l'algorithme de file d'attente répartie du cours.
La file d'attente se base sur les deux attributs de la classe net :
clock int: horloge logique du site ;requestTab [NB_SITES]Request: etat des requetes de demandes d'accès en section critique.
A partir de l'algorithme du cours, des méthodes ont été écrites :
func (n *Net) ReceiveCSRequest(): Envoi d'une requete d'accès au document partagéfunc (n *Net) receiveCSRelease(): Envoi d'une requete de libération du document partagéfunc (n *Net) receiveRequestMessage(received_msg Message): Traitement d'une requete d'accès au document partagé reçuefunc (n *Net) receiveReleaseMessage(msg Message): Traitement d'un message de liberation du document partagé reçufunc (n *Net) receiveAckMessage(msg Message): traitement d'un message d'acquittement reçufunc (n *Net) isValidRequest() bool: Comparaison des estampilles pour valider que le site a emis la requete la plus vieille et peut donc accéder à la section critique
Enfin, nous avons pu implémenter le programme en déroulant l'algorithme du cours.
Le code a été écrit en se basant sur l'algorithme d'instantané avec reconstitution de configuration (algorithme 11).
Les snapshots se basent sur les attributs suivants de la classe net :
color string: Couleur du siteinitator bool: Site initiateur du snapshot (faux si c'est un autre site)nbExpectedStates int: Nombre d'états devant être reçusnbExpectedMessages int: Nombre de messages devant être reçusstate *State: Etat local du siteglobalState *list.List: Etat Global
A partir de l'algorithme, des méthodes ont été écrites :
func (n *Net) InitSnapshot(): Début de l'instantanéfunc (n *Net) receiveStateMessage(msg Message): Reception d'un message de type étatfunc (n *Net) receivePrepostMessage(msg Message): Réception d’un message prepostfunc (n *Net) reinitializeAfterSnapshot(): Réinitialisation du site initiateur du snapshot après ce dernierfunc (n *Net) receiveEndSnapshotMessage(): Réinitialisation après la fin d'un snapshot
Enfin, nous avons pu implémenter le code en déroulant l'algorithme.
- Fonctions des logs :
func Info(id int, where string, what string): Log d'informationfunc Warning(id int, where string, what string): Log d'avertissementfunc Error(id int, where string, what string): Log d'erreur
- Variables :
var rouge stringvar orange stringvar raz stringvar cyan stringvar pid: id du processusvar stderr: logger correspondant à stderr
-
net.go
- Attributs
type Net struct { id int clock int requestTab [NB_SITES]Request messages chan MessageWrapper server *Server color string initator bool nbExpectedStates int nbExpectedMessages int state *State globalState *list.List }
- Methodes
NewNet(id int, port string, addr string) *Net: Constructeur d'un sitefunc (n *Net) ReceiveCSRequest(): Envoi d'une requete d'accès au document partagéfunc (n *Net) receiveCSRelease(): Envoi d'une requete de libération du document partagéfunc (n *Net) receiveExternalMessage(msg Message): Appel de la fonction approprié selon le type du messagefunc (n *Net) receiveRequestMessage(received_msg Message): Traitement d'une requete d'accès au document partagé reçuefunc (n *Net) isValidRequest() bool: Comparaison des estampilles pour valider que le site a emis la quete la plus vieille et donc peut accéder à la section critiquefunc (n *Net) receiveReleaseMessage(msg Message): Traitement d'un message de liberation du document partagé reçufunc (n *Net) receiveAckMessage(msg Message): Traitement d'un message d'acquittement reçufunc (n *Net) receiveStateMessage(msg Message): Traitement d'un message de type étatfunc (n *Net) receivePrepostMessage(msg Message): Traitement d'un message de type prepostfunc (n *Net) reinitializeAfterSnapshot(): Réinitialisation du site initateur après le snapshotfunc (n *Net) receiveEndSnapshotMessage(): Réinitialisation du site après le snapshotfunc (n *Net) ReadMessage(): Lit les messages sur l'entrée standard et les envoie ensuite sur le channel de communication du site pour qu'ils soient traités par MessageHandler().func (n *Net) writeMessage(msg Message): Ajout d'un message sur le canal de communication. Le message sera envoyé aux autres sites par MessageHandler()func (n *Net) MessageHandler(): Lit les messages reçu et les traite s'il sont destinés à ce site. Propage les messages qui sont destinés aux autres sitesfunc (n *Net) SendMessageFromServer(msg Message): Fonction utilisée pour envoyer un message depuis le clientfunc (n *Net) InitSnapshot(): Initialisation d'un snapshot
-
server.go
- Attributs
type Server struct { socket *websocket.Conn text []string id int net *Net command Command }
- Methodes
func NewServer(port string, addr string, id int, net *Net) *Server: Constructeur d'un serveurfunc (server *Server)createSocket(w http.ResponseWriter, r *http.Request): Creation de la websocketfunc (server *Server)Send(): envoi d'un message au format JSON au clientfunc (server *Server)closeSocket(): fermeture de la websocketfunc (server *Server)receive(): reception d'un message du clientfunc (server *Server)EditText(command Command): modification du texte du document avec la comande reçuefunc (server *Server)forwardEdition(command Command): propage la commande de modification du texte aux autres sitesfunc (server *Server)SendMessage(action string): modifie le texte, le propage aux autres sites et demande la libération de la section critique si le site est le demandeur de la section critique
-
Type :
type Message struct { From int To int Content string Stamp int MessageType string VectClock []int Color string }
type MessageWrapper struct { Action string Message Message }
type Request struct { RequestType string Stamp int }
type Command struct { Line int Action string Content string }
type State struct { Id int VectClock []int Text []string Review int }
type MessageToClient struct { Text []string Stamp int }
-
Fonctions :
func MessageFromString(raw string) Message: Transforme une string en un object Messagefunc (msg Message) ToString() string: Transforme un objet Message sous forme de stringfunc vectClockToString(vectClock []int)string : Transforme une horloge vectorielle en une stringfunc vectClockFromString(raw string) []int: Transforme une string en une horloge vectorielle sous forme de tableaufunc (s *State)VectClockIncr(otherClock []int, nbSites int): incrémente l'horloge vectoriellefunc (msg Message) ToStringForContent() string: Transforme un objet Message en une string pour être intégrée dans le Content d'un autre Messagefunc (msg Message) ConcernSnapshot() bool: Renvoie vrai si le message concerne le snapshotfunc (msg Message) Send(): Envoi d'un message formaté en string sur la sortie standardstdoutfunc CommandFromString(raw string) Command: Transforme une string en un objet Commandfunc (command Command) ToString() string: Transforme un objet Command en une stringfunc NewState(id int, text []string, nbSites int) *State: Constructeur d'un objet Statefunc StateFromString(raw string) State: Transforme une string en un objet Statefunc (s *State) ToString() string: Transforme un objet State en une stringfunc textToString(text []string) string: Transforme un texte en une stringfunc textFromString(raw string) []string: Transforme une string en un texte

