2009-06-08 5 views
3

est-il un moyen facile d'expirer une instruction SQL de sorte qu'il échouera au lieu d'attendre (par exemple livrer un jeu de résultats vide ou un message d'erreur ou autre sinon) je peux laisser la réservation de ressources d'un travail échouer et donner une autre chance à un autre? Je cherche une option DBI que j'ai oubliée jusqu'ici; m'envoyer des SIGALRM à moi-même pour me suicider n'est pas ce que j'ai en tête (bien que je doive avoir recours à ça si je le devais).Comment temporiser un "sélectionner pour la mise à jour" dans Oracle en utilisant Perl DBI

Le code snipé est pseudo-réduit et raccourci à l'extrême, mais j'espère que vous allez attraper la dérive.

my $sql = "SELECT one, two, three FROM sometable WHERE this = ? AND that = ?"; 
my $sth = $self->make_handle($sql); 
eval { 
    foreach my $this (sort keys %needed_ressources) { 
     # vvv This is where the idle time is spent vvv 
     $sth->execute($this, $that) or die("DB connection gone?!"); 
     # ^^^ This is where the idle time is spent ^^^ 
     my ($one, $two, $three) = $sth->fetchrow_array(); 
     unless($one) { # undefined record set == not found 
      $self->{DB_HANDLE}->rollback(); 
      die("$this not defined for $that!"); 
     } 
    } 
    # If we haven't died so far, we can move on 
    foreach... #similar loop here doing the actual update statement 
    $self->{DB_HANDLE}->commit(); 
}; 
return(1) unless [email protected]; 
return(undef); 

Voici les détails gores pour l'intéressé:

Dans une application qui fait numbercrunching massivement parallèle il existe un mécanisme de verrouillage mis en œuvre qui utilise ressource une table d'oracle. Chaque tâche doit verrouiller un certain nombre de ressources à lire et/ou un certain nombre de ressources à écrire, et ne peut démarrer que si tous les verrous ont été acquis avec succès. Au lieu d'attendre patiemment que les ressources soient libérées, les tâches devraient simplement échouer et être relancées plus tard par leur maître (cela réduit le nombre de transactions ouvertes, tout en améliorant les performances en ayant plus de tâches autour de celles-ci). Bien sûr, avant de mettre à jour la table, chaque ligne est réservée à l'aide d'une instruction "SELECT ... FOR UPDATE", de sorte qu'Oracle utilise le verrouillage de ligne et que des transactions simultanées peuvent se produire sur la table. Afin de réduire davantage les conditions de course possibles et les blocages, tous les travaux sélectionnent d'abord leurs lignes de ressources, puis les verrouillent en utilisant la même commande avant d'effectuer la mise à jour.

À partir de la mise en œuvre actuelle, cela fonctionne très bien dans plus des cas. Mais, parce que le "Select for update" bloque jusqu'à ce qu'Oracle accorde effectivement le verrou de ligne, il peut toujours arriver qu'un travail soit inactif attendant ses ressources, et je suis après ceux-ci pour mieux utiliser la puissance de processeur disponible. C'est OK d'attendre une seconde ou deux, mais pas dix ou plus juste pour le verrouillage. Pour un verrouillage plus tard, l'attente est nécessaire bien sûr, de sorte que la définition de la connexion DB entière pour accepter uniquement les résultats immédiats ne fonctionnera pas.

Je suis toujours reconnaissant pour RTFM réponses aussi longtemps qu'ils pointent vers l'emplacement dans le M que je TF ont R ;-))

Merci beaucoup à l'avance
Olfan

+1

Qu'entendez-vous par "se suicider"? Vous pouvez configurer votre gestionnaire SIGALRM pour qu'il fasse ce que vous voulez. Essayez-vous simplement d'éviter complètement les signaux? – jiggy

+0

J'essaie d'avoir seulement le processus maître pour gérer les signaux. Peut-être que Perl peut le gérer, mais ma structure cérébrale interne n'est pas prête à avoir différentes manipulations de signaux dans les processus père et enfant. – Olfan

Répondre

7

Je pense que vous voulez le paramètre NOWAIT sur la clause FOR UPDATE. Si l'enregistrement ne peut pas être verrouillé, la sélection échouera ("ORA-00054: ressource occupée et acquérir avec NOWAIT spécifié") et vous pouvez gérer l'exception comme vous le souhaitez. Découvrez le SQL Reference manual. C'est pour 11g, mais la syntaxe n'a pas changé pour plusieurs versions maintenant.

Une autre option consiste à attendre: "FOR UPDATE WAIT 3" attendra 3 secondes pour que le verrou soit acquis plutôt que d'échouer immédiatement.

+1

C'est juste génial, merci. Pourquoi bricoler avec Perl et DBI quand le SQL lui-même apporte déjà l'option que je veux? ;-) Il est déjà implémenté et sera mis en ligne dans la prochaine fenêtre de changement possible. Merci encore. – Olfan

+0

Perl/DBI a un plus grand quotient geek ;-) – DCookie

+0

C'est en live, avec le temps d'attente étant une option configurable. Bien que la plupart du temps ce changement sauve est passé juste en attente de stockage de masse (ma prochaine cible ;-), l'utilisation globale du processeur (== débit brut) a augmenté de près de 2%, ce qui en vaut la peine. – Olfan

2

En fait, SIGALRM peut-être pas si mal après tout. Certaines options sont répertoriées here.

+0

Bien sûr, vous avez raison. Mais je veux vraiment empêcher les processus de travail d'implémenter leur propre gestion du signal, surtout quand elle diffère de celle mise en œuvre par leur père. – Olfan

Questions connexes