Forum Programmation.perl fork et mysql

Posté par  .
Étiquettes : aucune
0
9
mai
2005
Bonjour,

J'ai un script qui se connecte à une base de donnée mysql et qui exécute des requêtes (avec le module DBI), jusqu'ici aucun souci. Dans ce script je suis amené à faire un fork pour pouvoir exécuter quelques commandes (plutôt longues en termes de temps...) en parrallèle. Mais, à la fin de l'exécution du fils (que je termine par un exit; , je perds automatiquement la connexion mysql et le programme père s'arrète du coup également avec le message suivant :

DBD::mysql::st execute failed: MySQL server has gone away at ./fork.pl line 17.

La ligne 17 est l'endroit ou dans le père tente d'exécuter une requête une fois que son fils est "mort".



#!/usr/bin/perl -w
use DBI;
$u = 0;

$dbh = DBI->connect( "DBI:mysql:database=mabase;host=localhost.localdomain",
"root", "passwd", { 'RaiseError' => 1 } );

####################################################################################
# BOUCLE 1 (BOUCLE "INFINIE")
####################################################################################
while (1) {
####################################################################################
# REQUETE PRINCIPALE : SELECTION DE LA TABLE UTILISATEUR AVEC TOUS CES CHAMPS
####################################################################################
$query = "select * from utilisateur";
$sth = $dbh->prepare($query);
$res = $sth->execute; # ICI C'EST LA LIGNE 17

$child = fork;
if ( $child == 0 ) {
print "Dans le fils\n";
$i = 0;
while ( $i < 100 ) {
print "Je suis dans le fils" . $u . " " . $i . "\n";
$i = $i + 1;
}
exit;
}
$u = $u + 1;
} # while(1) FIN BOUCLE 1 (BOUCLE "INFINIE")
$sth->finish;
$dbh->disconnect;


voici la trace de l'exécution :

Dans le fils
Je suis dans le fils0 0
Je suis dans le fils0 1
Je suis dans le fils0 2
Je suis dans le fils0 3
Je suis dans le fils0 4
Je suis dans le fils0 5
Je suis dans le fils0 6
Je suis dans le fils0 7
Je suis dans le fils0 8
Je suis dans le fils0 9
Je suis dans le fils0 10
Je suis dans le fils0 11
Je suis dans le fils0 12
Je suis dans le fils0 13
Je suis dans le fils0 14
Je suis dans le fils0 15
Je suis dans le fils0 16
Je suis dans le fils0 17
Je suis dans le fils0 18
Je suis dans le fils0 19
Je suis dans le fils0 20
Je suis dans le fils0 21
Je suis dans le fils0 22
Je suis dans le fils0 23
Je suis dans le fils0 24
Je suis dans le fils0 25
Je suis dans le fils0 26
Je suis dans le fils0 27
Je suis dans le fils0 28
Je suis dans le fils0 29
Je suis dans le fils0 30
Je suis dans le fils0 31
Je suis dans le fils0 32
Je suis dans le fils0 33
Je suis dans le fils0 34
Je suis dans le fils0 35
Je suis dans le fils0 36
Je suis dans le fils0 37
Je suis dans le fils0 38
Je suis dans le fils0 39
Je suis dans le fils0 40
Je suis dans le fils0 41
Je suis dans le fils0 42
Je suis dans le fils0 43
Je suis dans le fils0 44
Je suis dans le fils0 45
Je suis dans le fils0 46
Je suis dans le fils0 47
Je suis dans le fils0 48
Je suis dans le fils0 49
Je suis dans le fils0 50
Je suis dans le fils0 51
Je suis dans le fils0 52
Je suis dans le fils0 53
Je suis dans le fils0 54
Je suis dans le fils0 55
Je suis dans le fils0 56
Je suis dans le fils0 57
Je suis dans le fils0 58
Je suis dans le fils0 59
Je suis dans le fils0 60
Je suis dans le fils0 61
Je suis dans le fils0 62
Je suis dans le fils0 63
Je suis dans le fils0 64
Je suis dans le fils0 65
Je suis dans le fils0 66
Je suis dans le fils0 67
Je suis dans le fils0 68
Je suis dans le fils0 69
Je suis dans le fils0 70
Je suis dans le fils0 71
Je suis dans le fils0 72
Je suis dans le fils0 73
Je suis dans le fils0 74
Je suis dans le fils0 75
Je suis dans le fils0 76
Je suis dans le fils0 77
Je suis dans le fils0 78
Je suis dans le fils0 79
Je suis dans le fils0 80
Je suis dans le fils0 81
Je suis dans le fils0 82
Je suis dans le fils0 83
Je suis dans le fils0 84
Je suis dans le fils0 85
Je suis dans le fils0 86
Je suis dans le fils0 87
Je suis dans le fils0 88
Je suis dans le fils0 89
Je suis dans le fils0 90
Je suis dans le fils0 91
Je suis dans le fils0 92
Je suis dans le fils0 93
Je suis dans le fils0 94
Je suis dans le fils0 95
Je suis dans le fils0 96
Je suis dans le fils0 97
Je suis dans le fils0 98
Je suis dans le fils0 99
DBD::mysql::st execute failed: MySQL server has gone away at ./fork.pl line 17.
DBD::mysql::st execute failed: MySQL server has gone away at ./fork.pl line 17.


si quelqu'un pouvait m'aider...
  • # dans MySQL : show variables;

    Posté par  . Évalué à 1.

    et regarde max_connections

    Chez moi, il vaut 100... et chez toi, ça plante à 100 connections... hasard ?
    • [^] # Re: dans MySQL : show variables;

      Posté par  (site web personnel) . Évalué à 3.

      Ca plante à 100 chez lui parce qu'il fais un while de 100 et qu'après c'est le processus père qui reprend la main.

      while ( $i < 100 )

      aucun rapport avec le max_connexion... enfin je pense pas.
    • [^] # Re: dans MySQL : show variables;

      Posté par  . Évalué à 2.

      merci de ta réponse,
      moi aussi max connection est à 100 :

      mysql> show variables;
      ...
      | max_connections | 100 |
      ...


      mais, je ne pense pas que cela vienne de là car si j'enlève le fork et son test
      (if ( $child == 0 )), ca boucle infiniement sans problème...

      le programme il s'arrête seulement après l'exécution du premier fils... je comprend pas...
    • [^] # Re: dans MySQL : show variables;

      Posté par  . Évalué à 1.

      Il n'y a pas 100 connexions, c'est le fils qui compte jusqu'à 100 avant de se terminer.

      Le fils doit fermer la connexion mysql lors de sa sortie. Il vaudrait peut-être mieux utiliser connect_cached dans ce cas ou mettre connect dans BOUCLE 1.
      • [^] # Re: dans MySQL : show variables;

        Posté par  . Évalué à 1.

        effectivement cela ne vient pas du nombre de connexions. Le problème comme tu me la indiqué, viendrait du fait que le fils ferme la connexion en se terminant. Comme tu me l'as dit, j'ai utilisé connect_cached à la place de connect et j'ai été obligé de le mettre dans la boucle infine. Cela ne marche toujours pas : j'ai des comprtement différents sur plusieurs exécutions... dépendant d'où est rendu le père quand un fils se termine!

        j'ai essayé sans succès prepare_cached à la place de prepare... je désespère là.

        Je peux comprendre que le fils termine la connexion... mais comment la récupérer surtout que l'on ne sait pas où se trouve le père quand le fils se termine...


        #!/usr/bin/perl -w
        use DBI;
        $u = 0;

        ####################################################################################
        # BOUCLE 1 (BOUCLE "INFINIE")
        ####################################################################################
        while (1) {

        $dbh =
        DBI->connect_cached(
        "DBI:mysql:database=archive;host=localhost.localdomain",
        "root", "mysqlpwd", { 'RaiseError' => 1 } );

        ####################################################################################
        # REQUETE PRINCIPALE : SELECTION DE LA TABLE UTILISATEUR AVEC TOUS CES CHAMPS
        ####################################################################################
        $query = "select * from utilisateur";
        $sth = $dbh->prepare($query);
        $res = $sth->execute;# (c'est la ligne 20)

        $child = fork;
        if ( $child == 0 ) {
        print "Dans le fils n° ".$u."\n";
        exit;
        }
        print "Dans le père\n";
        $u = $u + 1;
        }# while(1) FIN BOUCLE 1 (BOUCLE "INFINIE")
        $sth->finish;
        $dbh->disconnect;


        voici la trace :


        [root@localhost perl]# ./fork.pl
        Name "main::res" used only once: possible typo at ./fork.pl line 20.
        Dans le fils n° 0
        Dans le père
        Dans le fils n° 1
        Dans le père
        Dans le fils n° 2
        Dans le père
        Dans le fils n° 3
        Dans le père
        Dans le fils n° 4
        Dans le père
        Dans le fils n° 5
        Dans le père
        Dans le fils n° 6
        Dans le père
        Dans le fils n° 7
        Dans le père
        Dans le fils n° 9
        Dans le père
        Dans le fils n° 10
        Dans le père
        Dans le fils n° 8
        DBD::mysql::st execute failed: MySQL server has gone away at ./fork.pl line 20.
        DBD::mysql::st execute failed: MySQL server has gone away at ./fork.pl line 20.


        plusieurs exécution ne donnent pas les même trace...mais cela fini par le même message d'erreur.
        • [^] # Re: dans MySQL : show variables;

          Posté par  . Évalué à 2.

          D'après la doc de perl sur exit


          The exit() function does not always exit immediately. It calls any defined "END" routines first, but these "END" routines may not themselves abort the exit. Likewise any object destructors that need
          to be called are called before the real exit. If this is a problem, you can call "POSIX:_exit($status)" to avoid END and destructor processing. See perlmod for details.


          Pas testé mais je pense que dans ce cas tu devras gérer toi même la destruction des objets avant la fermeture du fils.
          • [^] # Re: dans MySQL : show variables;

            Posté par  . Évalué à 1.

            Merci de ta réponse.

            mais il n'est pas génant (dans mon cas) que le ou fils ne se termine pas immédiatement après que je veille le détruire.

            En fait ce que je voudrais c'est ouvrir une connexion mysql et ne jamais la fermer.... Cela m'a l'air impossible puisque apparemment chaque fils cloture la connexion...

            biensur, si je met le connect dans la boucle infinie (connect_cached plutot), cela fait une reconnection de la base. Le problème est que le père se trouve "n'importe où" lorsque le fils se termine, il peut se trouver par exemple en train d'exécuter une requete alors que la BDD n'est plus connectée....

            je ne sais plus quoi faire...
            • [^] # Re: dans MySQL : show variables;

              Posté par  . Évalué à 2.

              > mais il n'est pas génant (dans mon cas) que le ou fils ne se termine
              > pas immédiatement après que je veille le détruire.

              Ben si puisque c'est ça qui ferme la connexion. La doc (perlfunc) dit que la sortie n'est pas immédiate car cette fonction fait le ménage avant de vraiment quitter et qu'il est possible de l'éviter en utilisant le module POSIX.

              Remplace le exit du fils par POSIX:_exit($status) pour voir.
              • [^] # Merci!

                Posté par  . Évalué à 1.

                J'ai remplacé exit par POSIX:_exit($status) et le programme perl fait désormais ce que je veux : ne pas cloturer la connexion quand le fils termine !

                Grand Merci pi6Lohe! (et les autres aussi.)

                je n'aurais pas trouvé tout seul, d'ailleurs j'allais abandonner.. merci beaucoup!

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.