Les sections ci-dessous décrivent certains scénarios d'interblocage courants et des suggestions permettant de les éviter.
L'exception suivante s'affiche :
com.ibm.websphere.objectgrid.plugins.LockDeadlockException: Message
Ce
message représente la chaîne transmise en tant que paramètre lorsque l'exception est créée et émise.Description : lorsqu'une transaction ou un client demande qu'un verrou doit être octroyé pour une entrée de mappe spécifique, la demande attend généralement que le client en cours lève le verrou avant d'être envoyée. Si la demande de verrou reste inactive pendant une longue période et qu'aucun verrou n'est jamais accordé, exception LockTimeoutException est créée pour empêcher un interblocage, qui est décrit plus en détail dans la section suivante. il est fort probable que vous receviez cette exception lorsque vous utilisez une stratégie de verrouillage pessimiste, car le verrou n'est jamais levé jusqu'à la validation de la transaction.
Extraire plus de détails :
L'exception LockTimeoutException contient la méthode getLockRequestQueueDetails qui renvoie une chaîne. Vous pouvez utiliser cette méthode pour visualiser la description détaillée de la situation qui déclenche l'exception. Voici un exemple de code qui intercepte l'exception et affiche un message d'erreur.
try {
...
}
catch (LockTimeoutException lte) {
System.out.println(lte.getLockRequestQueueDetails());
}
lock request queue
−>[TX:163C269E−0105−4000−E0D7−5B3B090A571D, state =
Granted 5348 milli−seconds ago, mode = U]
−>[TX:163C2734−0105−4000−E024−5B3B090A571D, state =
Waiting for 5348 milli−seconds, mode = U]
−>[TX:163C328C−0105−4000−E114−5B3B090A571D, state =
Waiting for 1402 milli−seconds, mode = U]
try {
...
}
catch (ObjectGridException oe) {
Throwable Root = findRootCause( oe );
if (Root instanceof LockTimeoutException) {
LockTimeoutException lte = (LockTimeoutException)Root;
System.out.println(lte.getLockRequestQueueDetails());
}
}
Solution : une exception LockTimeoutException empêche les blocages possibles dans votre application. Une exception de ce type se produit lorsque l'exception attend un laps de temps défini. Vous pouvez définir le délai d'attente de l'exception à l'aide de la méthode setLockTimeout(int) qui est disponible pour la mappe de sauvegarde BackingMap. Si aucun interblocage réel n'existe dans l'application, ajustez le délai d'attente de verrouillage pour éviter le LockTimeoutException.
ObjectGrid objGrid = new ObjectGrid();
BackingMap bMap = objGrid.defineMap("MapName");
bMap.setLockTimeout(30);
Utilisez l'exemple précédent codé en dur pour définir ObjectGrid et les propriétés de la mappe. Si vous créez ObjectGrid à partir d'un fichier XML, définissez l'attribut LockTimeout dans l'élément backingMap. Voici un exemple d'élément backingMap qui définit une valeur LockTimeout de mappe à 30 secondes.
<backingMap name="MapName" lockStrategy="PESSIMISTIC" lockTimeout="30">
Description : les scénarios suivants décrivent comment des interblocages peuvent se produire lors de l'accès à une clé unique à l'aide d'un verrou S mis à jour ultérieurement. Lorsque cette situation se produit sur deux transactions simultanément, un interblocage a lieu.
Unité d'exécution 1 | Unité d'exécution 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Chaque unité d'exécution effectue une transaction indépendante. |
2 | map.get(key1) | map.get(key1) | Verrou S octroyé pour les deux transactions pour key1 |
3 | map.update(Key1,v) | Aucun verrou U. Mise à jour effectuée dans le cache transactionnel. | |
4 | map.update(key1,v) | Aucun verrou U. Mise à jour effectuée dans le cache transactionnel | |
5 | session.commit() | Bloquée : le verrou S pour key1 ne peut pas être mis à niveau vers un verrou X car l'unité d'exécution 2 comporte un verrou S. | |
6 | session.commit() | Interblocage : le verrou S pour key1 ne peut pas être mis à niveau vers un verrou X car l'unité d'exécution 1 comporte un verrou S. |
Unité d'exécution 1 | Unité d'exécution 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Chaque unité d'exécution effectue une transaction indépendante. |
2 | map.get(key1) | Verrou S octroyé pour key1 | |
3 | map.getForUpdate(key1,v) | Verrou S mis à niveau vers un verrou U pour key1. | |
4 | map.get(key1) | Verrou S octroyé pour key1 | |
5 | map.getForUpdate(key1,v) | Bloquée : T1 comporte déjà un verrou U. | |
6 | session.commit() | Interblocage : le verrou U pour key1 ne peut pas être mis à niveau. | |
7 | session.commit() | Interblocage : le verrou S pour key1 ne peut pas être mis à niveau. |
Unité d'exécution 1 | Unité d'exécution 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Chaque unité d'exécution effectue une transaction indépendante. |
2 | map.get(key1) | Verrou S octroyé pour key1 | |
3 | map.getForUpdate(key1,v) | Verrou S mis à niveau vers un verrou U pour key1. | |
4 | map.get(key1) | Verrou S octroyé pour key1 | |
5 | map.getForUpdate(key1,v) | Bloquée : unité d'exécution 1 comporte déjà un verrou U. | |
6 | session.commit() | Interblocage : le verrou U pour key1 ne peut pas être mis à niveau vers un verrou X car l'unité d'exécution 2 comporte un verrou S. |
Unité d'exécution 1 | Unité d'exécution 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Chaque unité d'exécution effectue une transaction indépendante. |
2 | map.getForUpdate(key1) | Verrou U octroyé à l'unité d'exécution 1 pour key1. | |
3 | map.getForUpdate(key1) | Demande de verrou U bloquée. | |
4 | map.update(key1,v) | <bloquée> | |
5 | session.commit() | <bloquée> | Le verrou U pour key1 peut être mis à niveau vers un verrou X. |
6 | <libérée> | Le verrou U est finalement octroyé à key1 pour l'unité d'exécution 2. | |
7 | map.update(key2,v) | Verrou U octroyé à l'unité d'exécution 2 pour key2. | |
8 | session.commit() | Le verrou U pour key1 peut être mis à niveau vers un verrou X. |
Description : ce scénario décrit ce qui se produit si deux transactions tentent de mettre à jour la même entrée et maintiennent des verrous S sur les autres entrées.
Unité d'exécution 1 | Unité d'exécution 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Chaque unité d'exécution effectue une transaction indépendante. |
2 | map.get(key1) | map.get(key1) | Verrou S octroyé pour les deux transactions pour key1 |
3 | map.get(key2) | map.get(key2) | Verrou S octroyé pour les deux transactions pour key2 |
4 | map.update(key1,v) | Aucun verrou U. Mise à jour effectuée dans le cache transactionnel. | |
5 | map.update(key2,v) | Aucun verrou U. Mise à jour effectuée dans le cache transactionnel. | |
6. | session.commit() | Bloquée : le verrou S pour key1 ne peut pas être mis à niveau vers un verrou X car l'unité d'exécution 2 comporte un verrou S. | |
7 | session.commit() | Bloquée : le verrou S pour key2 ne peut pas être mis à niveau car l'unité d'exécution 1 comporte un verrou S. |
Unité d'exécution 1 | Unité d'exécution 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Chaque unité d'exécution effectue une transaction indépendante. |
2 | map.getForUpdate(key1) | Verrou U octroyé à la transaction T1 pour key1. | |
3 | map.getForUpdate(key1) | Demande de verrou U bloquée. | |
4 | map.get(key2) | <bloquée> | Verrou S octroyé pour T1 pour key2 |
5 | map.update(key1,v) | <bloquée> | |
6 | session.commit() | <bloquée> | Le verrou U pour key1 peut être mis à niveau vers un verrou X. |
7 | <libérée> | Le verrou U est finalement octroyé à key1 pour l'unité d'exécution 2. | |
8 | map.get(key2) | Verrou S octroyé à T2 pour key2 | |
9 | map.update(key2,v) | Verrou U octroyé à T2 pour key2 | |
10 | session.commit() | Le verrou U pour key1 peut être mis à niveau vers un verrou X. |
Unité d'exécution 1 | Unité d'exécution 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Chaque unité d'exécution effectue une transaction indépendante. |
2 | map.getforUpdate(key1) | map.getForUpdate(key2) | Verrou U octroyé pour key1 et key2 |
3 | map.get(key2) | map.get(key1) | Verrou S octroyé pour key1 et key2 |
4 | map.update(key1,v) | map.update(key2,v) | |
5 | session.commit() | Le verrou U ne peut pas être mis à niveau vers un verrou X car l'unité d'exécution 2 comporte un verrou S. | |
6 | session.commit() | Le verrou U ne peut pas être mis à niveau vers un verrou X car l'unité d'exécution 1 comporte un verrou S. |