Gestion de la concurrence¶
Ewt implémente deux méthodes de gestion de la concurrence : une méthode optimiste et une méthode pessimiste. Il est possible de spécifier pour chaque modèle le type de lock à utiliser. Sans indication particulière, Ewt applique le type optimiste par défaut.
Prérequis¶
Pour être fonctionnelle, la gestion du lock nécessite deux éléments au niveau de la base de données:
- L'ajout d'une colonne dédiée dans les tables de données. Cette
colonne sert à la fois pour le lock optimiste et le lock pessimiste.
La colonne allouée à ce rôle doit être déclarée via l'entréeadmin.lockingColName
du fichier de configuration. Le nom de colonne par défaut estewt_locking
. - Une table
ewt_locking
dans la base de données. Cette table permet d'enregistrer des informations complémentaires sur le type de lock, la date/heure à laquelle le lock est posé, l'utilisateur concerné, etc. Cette table est reprise automatiquement dans les scripts de création de tables.
Gestion optimiste¶
Le modèle de gestion optimiste est largement documenté en ligne. Le tutoriel en ligne disponible à l'adresse handling-concurrency donne une bonne vision de la manière selon laquelle la gestion optimiste de la concurrence est implémentée dans Ewt. De nombreuses autres sources peuvent être facilement trouvées sur la toile.
L'idée est de rester optimiste et de se dire que les conflits liés à la concurrence sont peu fréquents. La gestion de concurrence optimiste signifie qu'on laisse le conflit se produire et que l'on prend les mesures appropriées uniquement lorsque le conflit est constaté.
Une gestion optimiste s'applique en général aux enregistrements, c'est-à-dire aux tuples dans le cas de Ewt. Ainsi, pour implémenter ce type de gestion, chaque tuple contient une colonne réservée qui enregistre le numéro de version du tuple. Lorsqu'un utilisateur ouvre un dossier, le numéro de version est lu et conservé en mémoire au niveau du tuple (comme c'est le cas pour les autres données du tuple). Au moment de mettre à jour la valeur en base de données, le moteur adapte la requête de mise à jour de la manière suivante:
1 2 3 4 |
|
Si la requête réussit, cela signifie qu'aucun autre utilisateur n'a modifié le tuple. Si la requête échoue (c.-à-d. si elle ne modifie aucun tuple), cela signifie que le tuple a été modifié par un autre utilisateur (ou par le même utilisateur dans une autre session). L'application demande alors à l'utilisateur de régler le conflit.
On parle de gestion basée sur les tuples car le numéro de version est associé aux tuples. Toutefois il est possible de demander à Ewt d'agir au niveau du dossier et non uniquement au niveau du tuple lorsqu'un problème de concurrence est détecté.
Pour chaque modèle, on indiquera via l'attribut locklevel
le niveau de
lock attendu. Cet attribut peut prendre 3 valeurs:
tuple
: Cette valeur indique qu'un conflit de concurrence détecté par le moteur au niveau d'un tuple ne bloque l'enregistrement que du tuple en question. Les autres tuples du dossier (pour lesquels aucun conflit n'est détecté) sont quant à eux mis à jour dans la base de données.doc
: Cette valeur indique qu'un conflit de concurrence détecté par le moteur a une conséquence au niveau de tout le dossier et pas uniquement au niveau du/des tuple(s) concerné(s) par le conflit. En clair : dès que le moteur détecte un conflit sur l'un des tuples du dossier, aucune valeur du dossier n'est mise à jour en base de données.none
: Dans ce cas, aucun test de concurrence n'est effectué sur le modèle. Chaque enregistrement écrase la valeur précédente dans la mesure où elle existe encore. Il s'agit donc d'un mode "Client Wins" ou "Last in Wins". Ce type de lock est dangereux et n'est à utiliser que pour les cas où une perte de données est sans conséquence.
Il est également possible d'indiquer au modèle le comportement que doit avoir le moteur en cas de conflit. En règle générale, on propose deux choix à l'utilisateur en cas de conflit: forcer la mise à jour des valeurs ou recharger les valeurs de la base de données.
Exceptions¶
Lorsqu'un conflit de concurrence optimiste est détecté, le moteur génère une ou plusieurs exceptions que l'on retrouve dans l'arbre de sortie.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Qu'il s'agisse de concurrence optimiste comme ici ou pessimiste comme
présenté plus bas, les exceptions liées à un problème de concurrence ont
toutes le type lock
.
L'attribut subtype
reprend le type de lock appliqué. Dans le cas de la
gestion optimiste, la valeur est optimistic
.
L'attribut level
renseigne sur le niveau auquel l'exception est détectée.
Les valeurs fournies par cet attribut correspondent aux valeurs de
l'attribut locklevel
décrit plus haut dans ce document.
L'attribut target
contient l'hash du tuple sur lequel porte l'exception.
L'attribut cause
contient un identifiant d'erreur qui donne plus
d'information sur la nature du conflit rencontré. L'attribut peut prendre
les valeurs suivantes:
tupleModifiedElsewhere
tupleModifiedElsewhereWithSameValues
tupleNotFoundInDatabase
documentModifiedElsewhere
documentNotFoundInDatabase
Les exceptions de niveau "tuple" contiennent également un détail de champs
dont la valeur en base de données diffère de celle du dossier courant.
Chaque champ référencé contient un attribut target
qui reprend
l'identifiant de contexte du champ et une valeur.
Gestion pessimiste¶
Le modèle de gestion pessimiste est également largement documenté sur internet. Ici l'idée est de poser un lock systématique sur la ressource que l'on souhaite modifier, afin que personne d'autre ne puisse la modifier tant que le lock n'est pas libéré.
Lorsqu'un utilisateur ouvre un dossier, le moteur recherche s'il existe déjà un lock sur le dossier. Si c'est le cas, le dossier n'est accessible qu'en lecture. Si aucun lock préalable n'est posé, alors un lock est posé pour l'utilisateur. Le lock est levé à la fermeture ou à la suppression du dossier.
Dans Ewt, le principe est similaire, mais le lock est posé au niveau
des tuples: la colonne gérant le locking (ewt_locking
ou autre en
fonction de ce qui est défini dans la propriété admin.lockingColName
de la
config de l'application) est mise à jour sur chaque tuple du dossier. La
table ewt_locking
quant à elle enregistre des informations relatives au
contexte de verrouillage (date/heure, auteur, etc.)
Exceptions¶
Lorsqu'un conflit de concurrence pessimiste se produit, le moteur génère une ou plusieurs exceptions que l'on retrouve dans l'arbre de sortie. La structure est sensiblement la même que dans le cas de la gestion optimiste, à quelques différences près:
- L'exception ne contient pas d'élément
databaseValues
- L'attribut
subtype
prend la valeurpessimistic
-
L'attribut
cause
peut prendre les valeurs suivantes:cannotAcquireLock
cannotReleaseLock
corruptedLockingTable
tupleLockedElsewhere
tupleNotFoundInDatabase
documentNotFoundInDatabase
fatalLockingException