Comment testez-vous les conditions de course dans une base de données?

30

J'essaie d'écrire du code de base de données pour m'assurer qu'il n'est pas soumis aux conditions de concurrence, pour m'assurer que j'ai verrouillé les lignes ou les tables correctes. Mais je me demande souvent: mon code est-il correct? Est-il possible de forcer des conditions de concurrence existantes à se manifester? Je veux être sûr que si cela se produit dans un environnement de production, mon application fera ce qu'il faut.

Je sais généralement exactement quelle requête simultanée est susceptible de causer un problème, mais je ne sais pas comment les forcer à s'exécuter simultanément pour voir si le comportement correct se produit (par exemple, j'ai utilisé le bon type de verrou), que les bonnes erreurs sont jeté, etc.

Remarque: J'utilise PostgreSQL et Perl, donc si cela ne peut pas être répondu de manière générique, il devrait probablement être repensé en tant que tel.

Mise à jour: je préfère que la solution soit programmatique. De cette façon, je peux écrire des tests automatisés pour m'assurer qu'il n'y a pas de régressions.

xénoterracide
la source
Par «condition de concurrence», voulez-vous dire «impasse»?
Gaius
2
@Gaius ... non, même si je crois que c'est un résultat possible de certaines conditions de course
xenoterracide
Les conditions de concurrence @Gaius dans une base de données consisteraient à supprimer une table avant sa création ou à mettre à jour une ligne avant son insertion. En général, j'imagine qu'il est géré par la logique d'application en dehors de la base de données elle-même.
Mark D
mettre à jour une ligne avant qu'elle n'ait été insérée? cela ne causerait pas de problème de base de données. non, une condition de concurrence équivaudrait à récupérer une ligne et à la mettre à jour, mais demander à un autre utilisateur de la mettre à jour après la récupération de votre ligne mais avant le traitement de votre mise à jour.
xenoterracide
1
@MarkD - Non. Il existe de nombreux types de conditions de concurrence qui résultent de l'encapsulation incorrecte d'une unité de travail atomique dans votre base de données. Voici un exemple. Rappelez-vous, "une condition de course ou un danger de course est une faille dans un système ou un processus électronique par lequel la sortie ou le résultat du processus dépend de façon inattendue et critique de la séquence ou du calendrier d'autres événements ." ( source )
Nick Chammas

Réponses:

11

Je le fais tout le temps avec mes modules T-SQL.

Essentiellement, tout ce que vous devez faire est d' exécuter vos modules à partir de deux connexions ou plus dans une boucle pendant quelques minutes . En règle générale, tous les problèmes potentiels sont exposés en quelques minutes, en supposant que vous disposez d'une boîte SQL Server avec des processeurs décents.

J'ai écrit quelques exemples ici et ici .

AK
la source
4

Je travaille généralement avec l'outil de ligne de commande du SGBDR, en démarrant simplement 2 (ou plus) instances de la CLI. Vous pouvez ensuite rejouer un par un et comme une course (qui ressemblerait à un action-RPG) les instructions SQL que votre couche d'application envoie. Vous devriez expérimenter / sentir les systèmes de verrouillage en action car votre CLI "se bloquera" un peu, en attendant que les verrous soient libérés des autres CLI.

Si cela semble clair comme de la boue, n'hésitez pas à le dire ;-)

Julien
la source
pourriez-vous donner un exemple étape par étape? et les tests programmatiques peuvent-ils être écrits pour faire la même chose?
xenoterracide
1

Les conditions de concurrence nécessitent plusieurs threads d'exécution, donc pour tester unitaire ceci, vous devrez pouvoir démarrer un ou plusieurs threads. Dans Oracle, j'utiliserais DBMS_Scheduler pour exécuter un processus pour simuler un deuxième utilisateur. Si PostgreSQL / Perl a un moyen d'initier un second processus par programme, alors vous devriez pouvoir faire quelque chose comme ceci:

Processus 1 Processus 2

Démarrer le processus 2. >>                            
Délai pour permettre à 2 de faire son travail. 
. Verrouillez les lignes ou modifiez les données.
. Délai pour permettre à 1 de faire son travail.
Essayez de verrouiller des lignes ou de modifier des données. .
Vérifiez que la manipulation est correcte. .
Prend fin. .
                                                Prend fin.

Il est bon de voir comment réfléchir aux conditions de course et, surtout, comment les tester individuellement.

Leigh Riffel
la source
Je ne décrirais pas de tels tests comme des tests unitaires, car les tests unitaires doivent s'exécuter exactement de la même manière à chaque fois. Les conditions de course échouent par intermittence des processus impliqués, pas exactement de la même manière à chaque fois.
AK
@AlexKuznetsov Vous avez raison de dire que des conditions de course inattendues peuvent se manifester par intermittence, mais l'OP fait référence aux conditions attendues qu'il croit que le code gère. Ces conditions spécifiques peuvent être reproduites avec précision et la manipulation vérifiée par un test unitaire.
Leigh Riffel
-2

Tant que vous verrouillez des rangées, vous ne devriez pas vous retrouver dans une situation de course, car cela est généralement dû à l'absence de verrouillage.

Mais vous pourriez être bloqué si une question bloque votre question trop longtemps.

Ceci est difficile à tester car le temps des requêtes peut changer lorsque la base de données se développe.

Les requêtes qui fonctionnent correctement avec 100 000 lignes de données de test sortent du tableau avec 10 000 000 lignes.

Ce type de problème peut être très difficile à trouver à l'avance, mais de nombreuses bases de données ont une méthode d'identification des requêtes lentes.

En utilisant ce standard, vous devriez être en mesure de piéger toutes les requêtes en difficulté avec un avertissement suffisant.

Si vous verrouillez vous-même, c'est une autre histoire, mais là je ne peux pas vous aider.

Nick Chammas
la source
@darioo lol Je pensais que peut-être wn était un acronyme pour quelque chose ... idk ce qu'il voudrait dire par "faire le verrouillage par vous-même" S'il veut dire pas avec un ORM, j'ai vérifié le code que mon ORM sort il ne fait certainement pas le verrouillage à droite. C'est l'une des raisons pour lesquelles j'aimerais pouvoir tester des scénarios de conditions de course potentiels.
xénoterracide
Oui, je voulais dire propre, et normalement le pilote de base de données gère le verrouillage, la ligne, la table ou éventuellement le champ, mais j'ouvre juste la possibilité que vous utilisiez une base de données qui ne gère pas le verrouillage;)
.. Je suis à peu près sûr que si j'ai une transaction à déclarations multiples, ma base de données ne saura pas quelles lignes verrouiller automatiquement ... des choses comme celles- select for updateci n'existeraient pas si elles
existaient