PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 18/08/2011 14:29:54

Postgres.0
Membre

libpq Assynchrone

Bonjour,

quelqu'un peut il m'expliquer le fonctionnement de PQgetResult en mode assynchrone avec plusieurs requetes.
J'envoie plusieurs insert en une commande avec pqsendQuery(conn, commande).
Après, je boucle sur PQgetResult  :
   
       code = PQsendQuery(conn, query.c_str());

        while(NULL != (result_in = PQgetResult(conn)))
        {           
           
                 
             try
               {   
                   
                   if (PQresultStatus(result) != PGRES_COMMAND_OK)
                       
                    throw string (" problem   : ");
                   
                   
                   else if(strcmp(PQcmdTuples(result),"1") == 0)
                   { 
                      cout << "requete " << endl;         
                     
                  }
                   
               
               }
               catch(string const &chaine0)   
               {
               
                        if ( PQresultErrorField(result_in, PG_DIAG_SQLSTATE) == UNIQUE_VIOLATION )
                 
                          v_error_code =  "1000";
                       
                        else
                 
                           v_error_code = "99900";
                                         
                   
                           
                       
                        cerr  << chaine0   << PQresultErrorMessage (result) << endl;
                         
               }
                       
             
            PQclear(result);
         
           }

Mais le problème est que si la première requete contient une erreur, il va sortir de la boucle et du coup je ne pourrai plus controler les autres requetes.

Hors ligne

#2 18/08/2011 14:38:41

gleu
Administrateur

Re : libpq Assynchrone

Ça ne sert à rien de contrôler les autres requêtes si la première est en erreur. Elles ne seront de toute façon pas exécutées.


Guillaume.

Hors ligne

#3 18/08/2011 14:52:07

gleu
Administrateur

Re : libpq Assynchrone

Oubliez mon dernier commentaire, c'était stupide, on ne parle pas de transactions ici.


Guillaume.

Hors ligne

#4 18/08/2011 18:18:59

Postgres.0
Membre

Re : libpq Assynchrone

Quand j'affiche trois fois  le retour de PQgetResult(conn) ça me donne ça :

0x15e89a60   
0
0

   
Mon analyse est que 0x15e89a60 correpond au retour de la requete qui essaye d'inserer une ligne qui existe déjà, donc erreur.
En suite, tous les appels de PQgetresult pointe sur 0, alors qu'ils doivent pointer sur les requetes suivantes.

Hors ligne

#5 18/08/2011 22:34:01

gleu
Administrateur

Re : libpq Assynchrone

OK, j'ai donc fait un test avec un petit programme que j'ai fait rapidement ce soir :

include "postgres_fe.h"
#include "libpq-fe.h"

int
main(int argc, char **argv)
{
    PGconn          *conn;
    PGresult   *res;
    int status;

    /* connect to the database */
    conn = PQconnectdb("host=localhost port=5432 user=guillaume dbname=postgres0");
    if (!conn)
    {   
        fprintf(stderr, "test: could not connect to database\n");
        exit(1);
    }   

    /* make the call */
    status = PQsendQuery(conn, "INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (2); INSERT INTO t1 VALUES (3);");

    if (status == 0)
    {   
        fprintf(stderr, "error with the query\n");
        exit(1);
    }       

    /* check and deal with errors */
    while (res = PQgetResult(conn))
    {   
        printf("status: %d\n", PQresultStatus(res) > 2);
    }       

    /* cleanup */
    PQclear(res);

    PQfinish(conn);
    return 0;
}

Les trois requêtes sont bonnes et doivent bien insérées les données. L'exécution indique :

[master!git.pgstats]$ ./test 
status: 0
status: 0
status: 0

Ce qui est normal. Si on va dans psql, on voit ceci :

[master!git.pgstats]$ psql postgres0
psql (9.0.4)
Type "help" for help.

postgres0=# select xmin, * from t1;
 xmin  | c1 
-------+----
 83113 |  1
 83113 |  2
 83113 |  3
(3 rows)

xmin est une colonne système indiquant l'identifiant de transaction qui a créé la ligne. Dans ce cas, les trois lignes ont le même identifiant. Donc, PostgreSQL a considéré mes trois requêtes dans le même PQsendQuery comme étant une et une seule transaction. Du coup, il est normal qu'en cas d'erreur dans une des requếtes, on ait qu'un seul retour en erreur, comme ceci :

[master!git.pgstats]$ ./test 
status: 0
status: 1

La chaîne des trois requêtes était : INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (a); INSERT INTO t1 VALUES (3);

Autrement dit, la deuxième requête est fausse. On voit d'après la sortie du programme que la première requête s'exécute bien, que la deuxième échoue et que du coup la troisième n'est pas exécutée. Enfin, si je retourne dans psql, je me rends compte qu'aucune ligne n'a été insérée, y compris la première venant de la première requête qui avait réussi. Car elles sont toutes dans la même transaction et du coup, tout a échoué au final.

Bref, pour la faire courte, la chaîne dans PQsendQuery est considérée comme une transaction complète. La moindre requête qui échoue fait tout annuler. Et du coup, un seul message d'erreur.


Guillaume.

Hors ligne

#6 19/08/2011 09:34:49

Postgres.0
Membre

Re : libpq Assynchrone

Merci, je vois plus clair.
je me suis orienté vers  PQsendQueryParams pour essayer de  faire le même traitement, mais cette fois ci envoyer ligne par ligne sans attendre la reponse du serveur.
Il insert bien la première transaction, mais j'ai l'impression que l'on peut pas faire deux appels successifs de PQsendQueryParams sur la même connexion.

Dernière modification par Postgres.0 (19/08/2011 11:12:02)

Hors ligne

#7 19/08/2011 17:11:40

Postgres.0
Membre

Re : libpq Assynchrone

Au fait,

quand je fais plusieurs fois appel à PQsendQueryParams, ça marche la première fois.
Mais en suite, il m'affiche ce message : another command is already in progress

Est-ce-que vous pouriez me dire comment utiliser PSconsumeInput, PQbusy, pour éviter ce problème.

Hors ligne

#8 23/08/2011 23:15:28

gleu
Administrateur

Re : libpq Assynchrone

Je ne sais pas ce que vous herchez à obtenir avec PQconsumeInput et PQbusy mais ça ne vous aidera pas à exécuter une deuxième commande alors qu'une est déjà en cours d'exécution.


Guillaume.

Hors ligne

#9 25/08/2011 16:24:18

Postgres.0
Membre

Re : libpq Assynchrone

Je suis un peux surpris de me rendre compte qu'avec libpq la replication synchrone est plus rapide que le mode assynchrone.


Par rapport à ce que je veux obtenir, je vous fais une copie succinte de mon programme :

nb_transaction = 1000;

PQexec(conn_out, "FETCH   ALL IN cursor_select")

for (i=0; i<nb_transaction; i++)
   {                 
           
         /* requete déjà préparée avec PQsendPrepare*/

            status = PQsendQueryPrepared(conn,
                         l_query.c_str(),
                         v_nb_column,
                         (const char* const *)paramValues,
                         paramLengths,
                         paramFormats,
                         0); 
                         
               
                  if(PQconsumeInput(conn))
                   {     
                     if(PQisBusy(conn)) 
                      {
                         
                       sleep(2);  /* ici je perd du temps */
                       result_in = PQgetResult(conn);
                      }
                  else
                  {
                    result_in = PQgetResult(conn_in);
                  }             
             }
            else
             {
              cout << "erreur on :" << i << endl;
             
             }
}

j'essaye d'envoyer mes transactions de la manière ci-dessus, mais je remarque que je perd du temps et mon temps d'exection est moins bon

que quand j'envoie en mode synchrone (PQexecPrepared), confirmez s'il vous plait que c'est normal.


Je remarque surtout que si je n' appelle pas le sleep() ou bien si j'appelle sleep(1), je ne reçois que la moitié de mes transactions.

S'il vous plait aidez moi, car je ne vois plus du tout comment sortir de ce petrin.

Dernière modification par Postgres.0 (29/08/2011 11:57:51)

Hors ligne

#10 25/08/2011 18:55:36

gleu
Administrateur

Re : libpq Assynchrone

Je suis un peux surpris de me rendre compte qu'avec libpq la replication synchrone est plus rapide que le mode assynchrone.

Réplication est certainement pas le bon terme.

j'essaye d'envoyer mes transactions de la manière ci-dessus, mais je remarque que je perd du temps et mon temps d'exection est moins bon que quand j'envoie en mode synchrone

Je ne vois pas pourquoi vous vous attendez à de meilleurs résultats en asynchrone qu'en synchrone. Asynchrone ne veut pas dire parallélisé. Les requêtes vont être exécutées les unes après les autres. Sauf qu'en asynchrone vous vous ajoutez une attente de 2s. Vraiment rien d'étonnant.

S'il vous plait aidez moi, car je ne vois plus du tout comment sortir de ce petrin.

Difficile sans savoir ce que vous voulez faire.


Guillaume.

Hors ligne

#11 29/08/2011 11:30:40

Postgres.0
Membre

Re : libpq Assynchrone

Je suis obligé de me rajouter 2 ou 1 seconde d'attente, je n'ai pas le choix !
Avez vous idée de comment éviter de rajouter ces ou cette seconde d'attente ?
Pouvez vous me proposer, à partir du code,  un traitement assynchrone qui soit plus rapide que ce que j'ai écrit ?
Si je n'attend pas une seconde, j'aurais certainement des lignes de ma table qui ne seront pa envoyées.

Est-ce-que je peux faire un traitement assynchrone qui soit parrallèle ?

Dernière modification par Postgres.0 (29/08/2011 15:06:32)

Hors ligne

#12 29/08/2011 17:20:22

gleu
Administrateur

Re : libpq Assynchrone

Est-ce-que je peux faire un traitement assynchrone qui soit parrallèle ?

Oui, mais il vous faut plusieurs connexions (une connexion par "thread").


Guillaume.

Hors ligne

#13 30/08/2011 10:36:27

Postgres.0
Membre

Re : libpq Assynchrone

Ok,  si un thread plante, est-ce-que tout va planter ?
je pose cette question par rapport à la prod.


La, je vois qu'utiliser PQsendQueryPrepared, ne peux pas améliorer les performances.
alors j'ai decidé de revenir à PQsenquery, mais il demeurre un souci que je vais expliquer :

je declare un curseur binaire

DECLARE  cursor_select  BINARY CURSOR  FOR SELECT field1, field2, field3


FETCH  FORWARD ALL IN cursor_select

je construit mes requetes Insert1, Insert2, Insert3 avec PQgetvalue(result, i , j)


je fais une PQsendquery(Insert1; Insert2; Insert3;)

je boucle sur PQgetResult(conn_in).

Mais à la fin je n'ai rien inserer, y a t-il quelque chose de spécial que je de rajouter avec les curseurs binaires (un cast par exemple).

Dernière modification par Postgres.0 (30/08/2011 11:00:46)

Hors ligne

#14 30/08/2011 19:09:06

gleu
Administrateur

Re : libpq Assynchrone

Ok,  si un thread plante, est-ce-que tout va planter ?

Tout dépend du codage de votre application smile pg_restore réussit bien à utiliser plusieurs threads (sous Windows) et plusieurs processus (sous Linux).

La, je vois qu'utiliser PQsendQueryPrepared, ne peux pas améliorer les performances.

Il peut améliorer les performances mais pas dans votre cas.

Mais à la fin je n'ai rien inserer, y a t-il quelque chose de spécial que je de rajouter avec les curseurs binaires (un cast par exemple).

Je ne comprends pas la question.


Guillaume.

Hors ligne

#15 01/09/2011 09:28:32

Postgres.0
Membre

Re : libpq Assynchrone

Ma question se porte sur l'utilisation des curseurs binaire :

Leur declaration est simple, mais pour que les donnée du curseur  puissent etre envoyées par PQsendquery et surtout afficher par le serveur ou le client, faut il faire apelle à d'autre fonctions ou d'autres librairie.

Si vous avez un code qui utilise PQsendquery pour envoyer les données d'un curseur binaire, je suis preneur.

Hors ligne

Pied de page des forums