Didier Parigot

Zenith INRIA Team

INRIA Sophia Antipolis
Batiment Fermat, F109
2004 Route des Lucioles
BP 93
06902 Sophia Antipolis
Cedex France

Didier.Parigot@inria.fr
Tel : (33-4) 4 92 38 50 01
Fax : (33-4) 4 92 38 76 44



VirtPipes

Principes

Le but de ce framework est de limiter le nombre de TCP channel ouvert entre 2 JVMs : 1 seul tuyau TCP entre 2 JVM mais un nombre élevé de tuyau au niveau applicatif. Inspiré des tuyaux de communication de JXTA. SmartTools ¶

Plusieurs RDS ont été conçus avec ce principe et inria.lognet.ds.pon et inria.smarttools.ds.pon sont ceux qui utilise ce framework. Le principe est lors de la création d'un composant A, un tuyau virtuel est créé, qui permet de lire les messages addressés à ce composant. Plus précisement, pour les services "in" de ce composant, les messages arriveront sur ce tuyau. Le nom du tuyau, un numero unique, est publié sur un overlay (DHT) avec le principe décrit dans VirtPipes.

Afin de retrouver ce numéro unique, j'associe le nom du composant avec le numéro du tuyau. nom du composant -> UUID du tuyau virtuelle (Clef -> Valeur)

Lorsque un composant B est connecté à ce composant A, un proxy pour B est créé. le RDS de A recherche le tuyau virtuel d'entrée de B avec le nom du composant. Le proxy va pouvoir écrire dans ce tuyau. Pour les services "out" de A avec l'équivalent en service "in" pour B, le proxy va écrire les message (de sortie de A) pour être lu par B avec ce tuyau virtuel.

Puis surtout, entre deux framework OSGi (machines), une seule connection TCP est ouvrete. Cette connexion TCP va pouvoir supporter plusieurs communications (tuyau virtuel) entre les differents composants des deux machines. Le proxy écrit dans un tuyau virtuel préalablement créé par le vrai composant distant. Le RDS PON crée pour chaque composant local un objet reader qui lit les infos du VirtPipeInput?. Comme expliqué après (Scénario), les tuyaux sont enregistrés dans une DHT, et un composant distant est capable de récupérer les références de ce tuyau pour en créer un proxy du composant. Pour faire une communication bi-directionnelle, l'opération de connexion est effectué dans les deux sens, comme SmartTools le fait déjà en local.

Utilisation

Le VirtPipes module OSGi qui offre une abstraction de tuyaux de communication. Ce bundle dépend de open-chord (une DHT) et doit-être lancé au debut

La communication est basé sur Java NIO et TCP. Pour la couche utilisatrice de VirtPipes, 3 classes sont importantes : VirtPipeInput?, VirtPipeOutput? et VirtPipesService?.

Une instance de VirtPipesService? est créée lors du lancement du bundle et est publié en tant que service OSGi. Ce service OSGi est utile pour enregistrer des VirtPipesInput?.

Explication !

Une instance de VirtPipeInput? enregistré dans VirtPipesService?, aura comme effet une écoute de message dans le tuyau identifié par virtPipeInput.getId().

Une instance de VirtPipeOutput? doit avoir comme attribut VirtPipesService? pour envoyer des messages dans le tuyau virtuel identifié par virtPipeOutput.getId().

Voici un exemple pour un VirtPipeInput? :

public class Activator implements BundleActivator {

 public void start(BundleContext context) throws Exception {
  final ServiceReference ref = context.getServiceReference(VirtPipesService.class.getName());
  VirtPipesService vps = (VirtPipesService) context.getService(ref);
  if (vps != null) {
   vps.registerVirtPipe(new VirtPipeInput() {

    private UUID id = UUID.randomUUID();

    public UUID getId() {
     return id;
    }

    public void read(final ByteBuffer buffer) {
     System.out.println(new String(buffer.array()));
  }
 }

}

Voici une exemple pour un VirtPipeOutput? :

public class Activator implements BundleActivator {

 public void start(BundleContext context) throws Exception {
  final ServiceReference ref = context.getServiceReference(VirtPipesService.class.getName());
  VirtPipesService vps = (VirtPipesService) context.getService(ref);
  new VirtPipeOutput(vps, uuid /* some way to get an Id */) {

   public void error(Exception e) {
    e.printStackTrace();
   }

   public void virtPipeClosed() {}

  }.send(ByteBuffer.wrap("Hello World".getBytes()));
 }

}

Concept

Le concept est similaire aux tuyaux de JXTA. Globalement, les tuyaux sont virtuellement connectés par le framework, bien que rien ne laisse supposer qu'ils le sont réellement. Il n'y a aucune garantie que le message atteigne sa destination, surtout dans le cas multicast, dans le cas en routage et dans le cas où le tuyau ait été fermé avant ou pendant la transmission. Quelques travaux serait nécessaire pour palier à ces problèmes, mais ma vision est que nous pouvons construire un framework au-dessus de celui des tuyaux virtuels apportant cette fiabilité.

La propriété la plus importante est qu'il y a seulement une connexion TCP entre A et B et plusieurs tuyaux tuyaux virtuels passent à travers le tuyau de communication TCP entre la machine A et B.

Scénario

Dans cette section, je décris un petit scénario introduisant la transmission d'un message dans un tuyau virtuel unicast.

Vous pouvez voir qu'il y a deux notes 1 et 2 marquant 2 phases dans la réalisation de la connexion et de l'envoi du message.

Avant ces deux notes, c'est l'instanciation des clients et des frameworks VirtPipes et Channels.

Instanciation ou initialisation

Dans cette instanciation, il est important de noter que les VirtPipesServices? (VPS) enregistrent leurs coordonnées dans la DHT. Les coordonnées sont l'ensemble des adresses IP et le port, que possède la ServerSocket? géré par le VPS. Les coordonnées du VPS sont enregistrées dans la DHT, indéxé par "ips:UUID-VPS", où UUID-VPS est l'identifiant logique du VPS. Un préfix "ips:" est ajouté à l'identifiant UUID du VPS (UUID-VPS) afin de distinguer cette enregistrement avec l'enregistrement d'un VirtPipeInput? (voir paragraphe suivant). Cette entrée permet donc de connecter les VPS entre eux, car ils ont leurs adresses IP publiées dans la DHT.

A chaque VirtPipeInput? (VPI) enregistré dans un VPS, le VPS ajoute le VPI dans sa table de VPIs locaux et enregistre une entrée dans la DHT : "UUID du VPI" -> "UUID du VPS". Par exemple, quand B ouvre son tuyau virtuel d'entrée (VPI-B), son VPS-B va enregistrer dans la DHT cette entrée "UUID-VPI-B"->"UUID-VPS-B". Cette entrée permet donc d'identifier sur quels VPSs on doit envoyer la donnée, pour quelle soit dispatchée aux VPIs correspondant à la clé. Envoi d'une donnée de A vers B ¶

Le client A veut envoyer une donnée au tuyau virtuel UUID-VPI-B. Pour cela il a un objet VirtPipeOutput? (VPO) qui encapsule l'ID "UUID-VPI-B" du VPI-B distant et son VPS-A. Cet objet fait simplement VPS-A.send et peut recevoir des exceptions du VPS-A. Lorsque le VPS doit envoyer une donnée, il crée un VirtPipeMessage? ayant l'ID (UUID-VPI-B) et la donnée sous forme de ByteBuffer?. La forme envoyée dans le réseau est la suivante : 1 byte (type) + 128 bytes (UUID) + 16 bytes (size of ByteBuffer?) + SIZE bytes (the ByteBuffer? data).

Comme nous utilisons TCP, la transmission est garantie sur nous avons une connexion TCP au bon VPS. (ordre et intégrité des paquets)

Phase 1

Dans la phase notée 1, le VPS de A (VPS-A) n'est pas connecté au VPS de B (VPS-B), alors une connexion doit être réalisée. Pour cela, VPS-A interroge la DHT avec la clé "ips:UUID-VPS-B" et rappatrie la liste des IPs et le port du VPS-B.

Alors VPS A va tenter de se connecter avec chaque IP tant qu'il arrive enfin à avoir une connexion. Si ce n'était pas le cas, il faut chercher un autre VPS qui se chargera de router les messages vers VPS B. (Cette mécanique n'a pas été réalisée) La donnée est mise en attente dans une FIFO et on rend la main au programme principale.

Phase 2

ChannelsPool? reprend la main lorsque la connexion est réalisée (phase 2).

Juste après l'établissement de la connexion les VPS s'échange leur ID à l'aide d'un message VirtPipeMessage? avec un type INIT. Tous les autres messages destinés à des VPI ont un type NORMAL.

Enfin, il est possible d'envoyer la donnée au VPS-B. VPS B recevant un message, il recrée VirtPipeMessage?, utilise l'identifiant du VPI (UUID-VPI-B), retrouve le VPI dans sa table locale, et dispatche l'information.

Attention, lorsque VPI est invoqué, c'est toujours le thread de ChannelsPool?-B qui joue. Il vaut mieux redonner la main au ChannelsPool? tout de suite, pour qu'il puisse traiter la réception et l'émission des nombreux channels dont il a la charge.

Diagramme de Séquence VirtPipes

Structure

VirtPipeOutput? est basé sur une mécanique uniforme LogNet? Channels, qui propose de faire tourner l'ensemble des SelectableChannels? avec 1 thread. Cela est rendu possible grâce à Java NIO. ChannelsPool? doit être le plus générique possible, et agnostique des frameworks qui l'utilise. Pour cela un pattern stratégie est utilisé. Deux stratégies abstraites sont proposées ServerSocketStrategy?, qui ne fait qu'accepter des clients, et SocketStrategy? qui ne fait que envoyer et recevoir des données, finaliser la connexion. Ces stratégies doivent être implémenté par les frameworks clients, tel que VirtPipe?.

VirtPipe? est essentiellement constitué de VirtPipesService?, qui a pour rôle de gérer les tuyaux d'entrée, les connexions TCP vers les autres VPS, les données en attentes d'envoi ou de réception, de dispatcher ou router les informations.

VirtPipeInput? est important car il est nécessaire pour la couche supérieure, qui veut lire des données (être notifié de la réception d'un message).

VirtPipeOutput? est quant à lui utilisé, mais n'est pas fondamentalement nécessaire. Toutefois, il permet de lancer les exceptions à la couche supérieure.

Deux autres classes, qui ne sont pas représentées ici, SelectableVirtPipeInput? et SelectableVirtPipeOutput?, permettent de rendre les tuyaux virtuels respectivement InputStream? et OutputStream?. Pour cela, un Java NIO Pipe va réaliser la glue du framework VirtPipes vers la couche utilisatrice. Les demi-pipes gérés par VirtPipesService? tournent dans le thread ChannelsPool?, alors que les demi-pipes de la couche utilisatrice vont pouvoir utiliser leurs propres threads. Cela permet d'utiliser ObjectInputStream? et ObjectOutputStream? avec des tuyaux virtuels.

Diagramme de Classes VirtPipes


INRIA main page LIRMM main page