• Aucun résultat trouvé

2.2 EVOLUTION DE SCHEMAS

2.2.1 Gestion de l'évolution de schémas

2.2.2.1 Conversion 24

La conversion consiste en la mise à jour physique de toutes les instances qui ne sont pas compatibles avec la nouvelle définition de leurs classes d'appartenance. La conversion a pour objectif d'adapter les instances à la définition de leurs classes. Cette adaptation se traduit par une augmentation ou une réduction d'informations. Par exemple, l'ajout d'un attribut déclenche son ajout au niveau des instances. La valeur affectée à cet attribut peut être une valeur par défaut associée au type de l'attribut (null pour une classe, 0 pour un entier, etc.). Tandis que la suppression d'un attribut entraîne sa suppression dans les instances de la classe où il est supprimé.

La conversion peut être prise en compte par deux stratégies:

• La conversion immédiate où les instances sont mises à jour automatiquement dès l'évolution de leur classe. Cette technique, adoptée par GEMSTONE, offre l'avantage d'avoir à tout moment une base d'objets valide. Par contre, elle n'est pas très performante lorsque le nombre d'objets concernés est grand. Afin d'améliorer les performances de la répercussion, GEMSTONE regroupe les modifications concernant les mêmes instances, afin d'éviter les accès redondants aux objets. Par exemple, lorsqu'on ajoute plusieurs variables d'instances à une classe, il faut restructurer les instances, mais il faudrait le faire en un seul passage.

• La conversion différée ou retardée, adoptée entre autres par ORION [Banerjee87] et OTGEN

jusqu'à l'accès à toutes les instances concernées par la propagation. La conversion nécessite de gérer un historique des modifications de chaque classe. De plus, la conversion présente l'inconvénient de dégrader les performances du système car l'accès aux instances en est retardé.

2.2.2.2 Emulation

L'émulation, qui est l'approche suivie par le système ENCORE [Skarra86], consiste à masquer les évolutions de schémas au niveau des objets. Comme décrit au §2.2.1.2, l'évolution d'une classe engendre la création d'une version de cette classe. Il faut alors, pour chaque nouvelle version, programmer des procédures d'exception (pre et post handler) pour que la lecture et l'écriture d'un attribut ne provoquent pas d'erreur. Par exemple, si un attribut est supprimé dans une nouvelle version, il faut définir une exception en lecture qui renverra une valeur nulle et une exception en écriture qui sera sans effet.

ENCORE offre une autre façon de maintenir les instances en permettant une conversion

manuelle. En effet, si une classe est modifiée, les instances de cette classe peuvent être converties conformément à la nouvelle définition ("coercion"), et ceci par l'utilisation d'une opération ("convert"), qui contraint l'instance à correspondre à la nouvelle définition. Cette opération est explicite, elle est demandée par l'utilisateur. Lors de la reconfiguration des instances, les propriétés et les informations non présentes dans la nouvelle classe sont perdues, l'instance n'est plus valide pour l'ancienne classe. L'utilisation de la conversion ne résout pas le problème de l'utilisation des anciennes versions dans les programmes.

Cette même approche de conversion est utilisée dans CLOSQL [Monk93] pour adapter les instances aux différentes versions, à la différence que ce système propose le moyen de revenir en arrière, donc de convertir une instance vers une version antérieure.

L'émulation, en utilisant les exceptions, nécessite l'adaptation des versions de classes, pour permettre une bonne utilisation des instances des autres versions de classes. Cette émulation peut entraîner une dégradation des performances si le nombre d'incompatibilités entre les instances et les programmes augmente.

2.2.2.3 Versionnement

Cette stratégie est proposée dans [Clamen92], où l'évolution d'une classe engendre comme dans ENCORE la génération d'une version de classe, qui engendre à son tour une version de toutes les instances de la classe.

Après la modification d'une classe, lorsqu’on accède à une instance, le système crée une version de cette instance, conforme à la nouvelle définition de la classe. Des contraintes et des

dépendances de partage [Djeraba93a] sont spécifiées entre les versions d'instances d'une même classe. Elles décrivent les attributs partagés, les relations de dérivation des valeurs d'attributs et les dépendances générales entre les attributs des versions. La modification d'un attribut d'une version peut provoquer la mise à jour des autres versions (par exemple, recopie de valeurs) pour maintenir les contraintes et les dépendances. La mise à jour d'une version est différée jusqu’à son utilisation.

Cette approche préserve bien la cohérence des instances et la compatibilité des programmes, mais engendre un nombre important de versions (versions de classes et d'instances) ce qui complexifie la navigation dans la base.

2.2.3 Bilan

Il existe trois grandes approches complémentaires pour assurer l'évolution de schémas :

• L'approche par correction qui est un minimum à assurer ; cette approche est mise en œuvre par un ensemble d'opérations respectant les invariants du modèle de données.

• Le versionnement, où la modification d'une classe entraîne la création d'une version de classe, ce qui permet de garder un historique des changements et de faire partager les différentes versions de classes entre plusieurs utilisateurs.

• La réorganisation de classes qui consiste à reconstruire la hiérarchie de classes (cf. § 2.2.1.3).

Les deux dernières approches sont utilisées dans des bases (de données ou de connaissances) de taille assez importante ; elles constituent des pistes intéressantes pour le futur.

Dans les trois approches citées ci-dessus, le problème de l'impact des modifications de classes sur les instances n’est pas abordé. Il existe trois techniques pour assurer cet impact.

• La conversion, qui consiste à convertir les instances concernées par la modification de leur classes d'appartenance. La conversion peut être immédiate [Penney87], après la modification de la classe, ou différée [Banerjee87], lors de l'accès aux instances.

• L'émulation [Skarra86] qui a pour objectif de masquer la dérivation d'une version de classe par des procédures d'exceptions.

• Le versionnement [Clamen92] dont le but est de créer une version des instances pour chaque version de classe.

L'inconvénient commun à toutes ces approches est la forme sous laquelle se présente l'évolution de schémas. Souvent, il faut passer par des langages de programmation qui ne facilitent ni l'expression des besoins en évolution, ni la maintenance des opérations d'évolutions. L'inconvénient précédent oblige les concepteurs des systèmes à proposer une et une seule politique d'évolution de schémas, ce qui ne correspond pas souvent aux besoins des utilisateurs.

ADELE3 [Ahmed-Nacer94], à notre connaissance, est le seul système à proposer une notion de politique d’évolution qui permet d’associer à un type ou un schéma un ensemble de déclencheurs contrôlant leur évolution. Un schéma de l’application est défini par une composition de types ; redéfinir la politique par défaut revient à redéfinir la relation de composition de ce schéma, et d’associer à cette nouvelle relation des triggers qui expriment le contrôle de l’évolution du schéma. Le concept de politique ou de stratégie n’est pas défini clairement ; rien n’est dit sur l’organisation des politiques. De plus, le schéma décrivant l’évolution (ensemble des triggers) est intégré dans le schéma de l’application, ce qui ne facilite pas la réutilisation.