Plug-in de vérification et de comparaison des versions des objets mis en cache

Le plug-in OptimisticCallback permet de personnaliser les opérations de vérification et de comparaison des versions des objets du cache lorsqu'on utilise la stratégie de verrouillage optimiste.

Il est possible de fournir un objet connectable de rappel optimiste qui implémente l'interface com.ibm.websphere.objectgrid.plugins.OptimisticCallback. Pour les mappes d'entités, un plug-in OptimisticCallback hautes performances est automatiquement configuré.

Utilité

L'interface OptimisticCallback permet de fournir des opérations de comparaison optimiste entre les valeurs d'une mappe. Un plug-in OptimisticCallback est nécessaire lorsqu'on utilise la stratégie de verrouillage optimiste. Le produit fournit une implémentation par défaut d'OptimisticCallback. Mais, en principe, c'est à l'application de connecter sa propre implémentation de cette interface.

Implémentation par défaut

La structure eXtreme Scale fournit une implémentation par défaut de l'interface OptimisticCallback qui est utilisée si l'application ne connecte pas d'objet OptimisticCallback fourni par ses soins. L'implémentation par défaut retourne toujours la valeur spéciale NULL_OPTIMISTIC_VERSION comme objet version de la valeur et elle n'actualise jamais cet objet version. Cette action fait de la comparaison optimiste une fonction "no operation". Dans la plupart des cas, l'on ne souhaite pas que se produise une fonction "no operation" lorsqu'on utilise la stratégie de verrouillage optimiste. Vos applications doivent implémenter l'interface OptimisticCallback et connecter leurs propres implémentations OptimisticCallback afin de ne pas utiliser l'implémentation par défaut. Mais il existe au moins un scénario où l'implémentation OptimisticCallback fournie par défaut a toute son utilité. Prenons le cas de figure suivant :
  • Un chargeur est connecté pour la mappe de sauvegarde.
  • Le chargeur sait comment effectuer la comparaison optimiste sans l'assistance d'un plug-in OptimisticCallback.
Comment le chargeur peut-il effectuer une vérification optimiste des versions sans l'assistance d'un objet OptimisticCallback ? Le chargeur connaît l'objet de classe value et il sait quelle zone de l'objet value est utilisée comme valeur optimiste de version. Supposons, par exemple, que l'interface suivante soit utilisée pour l'objet value de la mappe Employee :
public interface Employee
{
    // Sequential sequence number used for optimistic versioning.
    public long getSequenceNumber();
    public void setSequenceNumber(long newSequenceNumber);
    // Other get/set methods for other fields of Employee object.
}

Dans cet exemple, le chargeur sait qu'il peut utiliser la méthode getSequenceNumber pour obtenir la version actuelle d'un objet value Employee. Le chargeur incrémente la valeur retournée pour générer un nouveau numéro de version avant d'actualiser le stockage de persistance avec la nouvelle valeur d'Employee. Dans le cas d'un chargeur JDBC (Java Database Connectivity), c'est le numéro actuel de séquence dans la clause WHERE d'une instruction SQL UPDATE surqualifiée qui est utilisé et le chargeur utilise le nouveau numéro de séquence qui est généré pour définir la colonne des numéros de séquence. Autre possibilité : le chargeur recourt à une certaine fonction fournie en dorsal, qui actualise automatiquement une colonne masquée utilisables pour la vérification optimiste des versions.

Dans certains cas, une procédure stockée ou déclencheur peut être utilisée pour aider à maintenir une colonne contenant les informations de version. Si le chargeur utilise l'une de ces techniques pour maintenir des informations optimistes de version, l'application n'aura pas besoin de fournir d'implémentation d'OptimisticCallback. L'implémentation par défaut d'OptimisticCallback est utilisable dans ce scénario car le chargeur peut vérifier les versions de manière optimiste sans l'assistance d'un objet OptimisticCallback.

Implémentation par défaut des entités

Les entités sont stockées dans l'ObjectGrid à l'aide d'objets tuple. Le comportement de l'implémentation par défaut d'OptimisticCallback est semblable à celui des mappes de non-entités. Mais la zone version dans l'entité est identifiée à l'aide de l'annotation @Version ou de l'attribut version dans le fichier XML de descripteur d'entités.

L'attribut version peut être de l'un des types suivants : int, Integer, short, Short, long, Long ou java.sql.Timestamp. Une entité ne doit avoir qu'un seul attribut version défini. L'attribut version ne doit être défini que pendant la construction. Une fois l'entité persistante, la valeur de l'attribut version ne doit pas être modifiée.

Si un attribut version n'est pas configuré et que l'on utilise la stratégie de verrouillage optimiste, le tuple tout entier est versionné en utilisant son état tout entier, ce qui est beaucoup plus onéreux.

Dans l'exemple qui suit, l'entité Employee a un attribut long de version nommé SequenceNumber :
@Entity
public class Employee {
private long sequence;
    // Sequential sequence number used for optimistic versioning.
    @Version
    public long getSequenceNumber() {
        return sequence;
    }
    public void setSequenceNumber(long newSequenceNumber) {
        this.sequence = newSequenceNumber;
    }
    // Other get/set methods for other fields of Employee object.
}

Ecrire un plug-in OptimisticCallback

Un plug-in OptimisticCallback doit implémenter l'interface OptimisticCallback et se conformer aux conventions habituelles des plug-in ObjectGrid. Pour plus d'informations, voir Interface OptimisticCallback.

La liste suivante décrit ou explique chacune des méthodes de l'interface OptimisticCallback :

NULL_OPTIMISTIC_VERSION

Cette valeur spéciale est retournée par la méthode getVersionedObjectForValue si l'implémentation d'OptimisticCallback ne requiert pas de vérification des versions. L'implémentation pré-intégrée de la classe com.ibm.websphere.objectgrid.plugins.builtins.NoVersioningOptimisticCallback utilise cette valeur car la vérification des versions est désactivée lorsque c'est cette implémentation qui est spécifiée pour le plug-in.

Méthode getVersionedObjectForValue

La méthode getVersionedObjectForValue peut retourner une copie de la valeur ou d'un attribut de la valeur qui peut être utilisée à des fins de vérification des versions. Cette méthode est appelée chaque fois qu'un objet est associé à une transaction. Lorsqu'aucune API Loader n'est connectée à une mappe de sauvegarde, cette dernière utilise cette valeur au moment de la validation afin d'effectuer une comparaison optimiste des versions. La comparaison optimiste des versions est utilisée par la mappe de sauvegarde pour s'assurer que la version n'a pas changé après le premier accès de cette transaction à l'entrée de mappe qui a été modifiée par cette transaction. Si entre-temps une autre transaction a modifié la version de cette entrée de mappe, la comparaison échoue et la mappe de sauvegarde affiche une exception OptimisticCollisionException pour forcer la transaction à s'annuler. Si une API Loader est connectée, la mappe de sauvegarde n'utilise pas les informations de vérification optimiste des versions. Car c'est à l'API Loader d'effectuer cette comparaison optimiste et d'actualiser les informations de version quand c'est nécessaire. Normalement, l'API Loader obtient l'objet de version initial du LogElement transmis à sa méthode batchUpdate, laquelle méthode est appelée lorsqu'une opération de vidage se produit ou lorsqu'une transaction est validée.

Le code suivant montre comment l'objet EmployeeOptimisticCallbackImpl utilise l'implémentation :
public Object getVersionedObjectForValue(Object value)
{
    if (value == null)
    {
        return null;
    }
    else
    {
        Employee emp = (Employee) value;
        return new Long( emp.getSequenceNumber() );
    }
}

Comme le montre l'exemple ci-dessus, l'attribut sequenceNumber est retourné dans un objet java.lang.Long object, attendu par l'API Loader, ce qui implique que la personne qui a écrit l'API soit a écrit l'implémentation EmployeeOptimisticCallbackImpl, soit a collaboré étroitement avec celle qui a implémenté EmployeeOptimisticCallbackImpl, notamment en se mettant d'accord sur la valeur retournée par la méthode getVersionedObjectForValue. Le plug-in OptimisticCallback par défaut retourne la valeur spéciale NULL_OPTIMISTIC_VERSION en tant qu'objet version.

Méthode updateVersionedObjectForValue

Cette méthode est appelée chaque fois qu'une transaction a actualisé une valeur et que l'on a besoin d'un nouvel objet versionné. Si la méthode getVersionedObjectForValue retourne un attribut de la valeur, cette méthode actualise normalement la valeur de l'attribut avec un nouvel objet version. Si la méthode getVersionedObjectForValue retourne une copie de la valeur, en principe, cette méthode n'effectue aucune action. Avec cette méthode, le plug-in OptimisticCallback par défaut n'effectue aucune action car l'implémentation par défaut de getVersionedObjectForValue retourne la valeur spéciale NULL_OPTIMISTIC_VERSION en tant qu'objet version. L'exemple qui suit montre l'implémentation utilisée par l'objet EmployeeOptimisticCallbackImpl qui est utilisé dans la section OptimisticCallback :
public void updateVersionedObjectForValue(Object value)
{
    if ( value != null )
    {
        Employee emp = (Employee) value;
        long next = emp.getSequenceNumber() + 1;
        emp.updateSequenceNumber( next );
    }
}

Comme le montre l'exemple ci-dessus, l'attribut sequenceNumber s'incrémente de un afin que, lors du prochain appel de la méthode getVersionedObjectForValue, la valeur java.lang.Long qui est retournée soit une valeur de type long, égale à celle du numéro de séquence d'origine. Plus un, par exemple, sera la version suivante de cette instance d'Employee. Il ressort de cet exemple que la personne qui a écrit l'API Loader soit a écrit l'implémentation EmployeeOptimisticCallbackImpl, soit a collaboré étroitement avec celle qui a implémenté EmployeeOptimisticCallbackImpl.

Méthode serializeVersionedValue

Cette méthode écrit dans le flux spécifié la valeur versionnée. Selon l'implémentation, la valeur versionnée peut être utilisée pour identifier les collisions de mises à jour optimistes. Dans certaines implémentations, la valeur versionnée est une copie de la valeur d'origine. D'autres implémentations peuvent avoir un numéro de séquence ou un autre objet pur indiquer la version de la valeur. Comme l'implémentation effective est inconnue, cette méthode est fournie pour effectuer la sérialisation appropriée. L'implémentation par défaut appelle la méthode writeObject.

Méthode inflateVersionedValue

Cette méthode prend la version sérialisée de la valeur versionnée et elle retourne l'objet effectif de la valeur versionnée. Selon l'implémentation, la valeur versionnée peut être utilisée pour identifier les collisions de mises à jour optimistes. Dans certaines implémentations, la valeur versionnée est une copie de la valeur d'origine. D'autres implémentations peuvent avoir un numéro de séquence ou un autre objet pur indiquer la version de la valeur. Comme l'implémentation effective est inconnue, cette méthode est fournie pour effectuer la désérialisation appropriée. L'implémentation par défaut appelle la méthode readObject.

Utiliser l'objet OptimisticCallback fourni par l'application

Deux approches permettent d'ajouter un plug-in OptimisticCallback dans la configuration BackingMap : la configuration XML et la configuration par programmation.

Configuration par programmation du plug-in OptimisticCallback

L'exemple qui suit montre comment une application peut par programmation connecter un objet OptimisticCallback pour la mappe de sauvegarde Employee dans l'instance ObjectGrid locale grid1 :
import com.ibm.websphere.objectgrid.ObjectGridManagerFactory;
import com.ibm.websphere.objectgrid.ObjectGridManager;
import com.ibm.websphere.objectgrid.ObjectGrid;
import com.ibm.websphere.objectgrid.BackingMap;
ObjectGridManager ogManager = ObjectGridManagerFactory.getObjectGridManager();
ObjectGrid og = ogManager.createObjectGrid( "grid1" );
BackingMap bm = dg.defineMap("employees");
EmployeeOptimisticCallbackImpl cb = new EmployeeOptimisticCallbackImpl();
bm.setOptimisticCallback( cb );

Configuration par XML du plug-in OptimisticCallback

L'application peut utiliser un fichier XML pour connecter son objet OptimisticCallback :
<?xml version="1.0" encoding="UTF-8"?>
<objectGridConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://ibm.com/ws/objectgrid/config ../objectGrid.xsd"
 xmlns="http://ibm.com/ws/objectgrid/config">
<objectGrids>
    <objectGrid name="grid1">
        <backingMap name="employees" pluginCollectionRef="employees" lockStrategy="OPTIMISTIC" />
    </objectGrid>
</objectGrids>

<backingMapPluginCollections>
    <backingMapPluginCollection id="employees">
        <bean id="OptimisticCallback" className="com.xyz.EmployeeOptimisticCallbackImpl" />
    </backingMapPluginCollection>
</backingMapPluginCollections>
</objectGridConfig>