IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

SQLite Discussion :

C++ : crash dans sqlite3_prepare


Sujet :

SQLite

  1. #1
    Membre averti
    Inscrit en
    Décembre 2007
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 16
    Par défaut C++ : crash dans sqlite3_prepare
    Bonjour à tous,

    j'ai mis en place un petit outil de test multithread de lecture /écriture de bases SQLITE (légères) en accès fréquent (toutes les 200/300 ms).
    l'application tourne bien jusqu'au moment où très aléatoirement je crashe lors d'une requête SELECT dans la fonction sqlite3_blob_close appelée au sein de la fonction sqlite3_prepare que j'appelle à haut niveau.

    j'ouvre à la base
    je crée ma requête SQL (valide)
    j'appelle sqlite3_prepare
    et boum (ça marche 20 fois, ou 200, c'est très aléatoire et puis d'un coup d'un seul ça plante) :
    "Exception non gérée... : violation d'accès lors de la lecture de l'emplacement ..."


    j'ai en gros une thread qui écrit et une autre qui lit
    Si je ne fais que lire la base, pas de problème,
    Si je ne fais qu'écrire la base, pas de problème,
    si une application écrit et plusieurs autres lisent, pas de problème non plus...
    mais en multi access avec une même application, il y a problème.

    Est ce un problème de mauvaise protection du code en gestion multi thread ?

  2. #2
    Membre expérimenté

    Inscrit en
    Décembre 2004
    Messages
    169
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 169
    Par défaut
    Citation Envoyé par viklaus83 Voir le message
    Bonjour à tous,

    j'ai mis en place un petit outil de test multithread de lecture /écriture de bases SQLITE (légères) en accès fréquent (toutes les 200/300 ms).
    l'application tourne bien jusqu'au moment où très aléatoirement je crashe lors d'une requête SELECT dans la fonction sqlite3_blob_close appelée au sein de la fonction sqlite3_prepare que j'appelle à haut niveau.

    j'ouvre à la base
    je crée ma requête SQL (valide)
    j'appelle sqlite3_prepare
    et boum (ça marche 20 fois, ou 200, c'est très aléatoire et puis d'un coup d'un seul ça plante) :
    "Exception non gérée... : violation d'accès lors de la lecture de l'emplacement ..."


    j'ai en gros une thread qui écrit et une autre qui lit
    Si je ne fais que lire la base, pas de problème,
    Si je ne fais qu'écrire la base, pas de problème,
    si une application écrit et plusieurs autres lisent, pas de problème non plus...
    mais en multi access avec une même application, il y a problème.

    Est ce un problème de mauvaise protection du code en gestion multi thread ?
    Sans trop connaitre ton code, je dirais que tu tentes d'écrire en simultané dans la base. Donc, l'un des processus obtient : SQLITE_BUSY (base de données en cours d'utilisation par un autre processus. SQLite tentera alors d'effectuer un ROLLBACK implicite pour une partie de la transaction... mais cela n'a peut-être rien à voir).
    Ensuite, il y a de grande chance pour que ton sqlite3_prepare ne soit pas valide dans ce cas précis (pourquoi ? impossible de répondre sans code). Ainsi, la fonction qui aurait du être préparée n'existe pas (pointeur nul par exemple) et ton exécution du SELECT suivant plante car SQLite fait alors appel à une adresse mémoire incorrecte.

    C'est une piste... rien de certain.
    a+

  3. #3
    Membre éclairé
    Inscrit en
    Juillet 2006
    Messages
    75
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 75
    Par défaut
    Sauf erreur de ma part SQLite n'est prévu pour des accès concurrenciels

  4. #4
    Membre expérimenté

    Inscrit en
    Décembre 2004
    Messages
    169
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 169
    Par défaut
    Citation Envoyé par SERTNM Voir le message
    Sauf erreur de ma part SQLite n'est prévu pour des accès concurrenciels
    Tu as partiellement raison : cf. la FAQ de la documentation officielle :

    (5) Can multiple applications or multiple instances of the same application access a single database file at the same time?

    Multiple processes can have the same database open at the same time. Multiple processes can be doing a SELECT at the same time. But only one process can be making changes to the database at any moment in time, however.

    SQLite uses reader/writer locks to control access to the database. (Under Win95/98/ME which lacks support for reader/writer locks, a probabilistic simulation is used instead.) But use caution: this locking mechanism might not work correctly if the database file is kept on an NFS filesystem. This is because fcntl() file locking is broken on many NFS implementations. You should avoid putting SQLite database files on NFS if multiple processes might try to access the file at the same time. On Windows, Microsoft's documentation says that locking may not work under FAT filesystems if you are not running the Share.exe daemon. People who have a lot of experience with Windows tell me that file locking of network files is very buggy and is not dependable. If what they say is true, sharing an SQLite database between two or more Windows machines might cause unexpected problems.

    We are aware of no other embedded SQL database engine that supports as much concurrancy as SQLite. SQLite allows multiple processes to have the database file open at once, and for multiple processes to read the database at once. When any process wants to write, it must lock the entire database file for the duration of its update. But that normally only takes a few milliseconds. Other processes just wait on the writer to finish then continue about their business. Other embedded SQL database engines typically only allow a single process to connect to the database at once.

    However, client/server database engines (such as PostgreSQL, MySQL, or Oracle) usually support a higher level of concurrency and allow multiple processes to be writing to the same database at the same time. This is possible in a client/server database because there is always a single well-controlled server process available to coordinate access. If your application has a need for a lot of concurrency, then you should consider using a client/server database. But experience suggests that most applications need much less concurrency than their designers imagine.

    When SQLite tries to access a file that is locked by another process, the default behavior is to return SQLITE_BUSY. You can adjust this behavior from C code using the sqlite3_busy_handler() or sqlite3_busy_timeout() API functions.
    Ainsi, je résume : on peut ouvrir et lire une base SQLite depuis plusieurs applications différentes, on ne peut écrire dans cette même base qu'un seul à la fois. Lorsqu'on verrouille une base pour écriture, les autres processus doivent attendre la fin de cette opération.

    Cela ne pose aucun problème lorsque la base est utilisée par php par exemple depuis un serveur Web car dans ce cas il n'y a qu'un seul processus à un instant t qui interprète le code php d'écriture. Par contre, si l'on développe son propre programme et que l'on attaque la base depuis plusieurs processus, il faut utiliser les règles de verrous (locks) et attendre la permission d'écrire ou de lire la base.

    Les accès concurrentiels sont donc permis sous SQLite.

  5. #5
    Membre averti
    Inscrit en
    Décembre 2007
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 16
    Par défaut
    Bonjour et merci Bigane de tes renseignements,

    tu me conseilles donc de rajouter des verrous "C++" sur le fichier BDD en plus du verrouillage que devrait effectuer SQLITE ?

    ou alors existe t'il un moyen de mieux protéger le code avec la librairie Sqlite ?

    Cdt,

  6. #6
    Membre expérimenté

    Inscrit en
    Décembre 2004
    Messages
    169
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 169
    Par défaut
    Citation Envoyé par viklaus83 Voir le message
    Bonjour et merci Bigane de tes renseignements,

    tu me conseilles donc de rajouter des verrous "C++" sur le fichier BDD en plus du verrouillage que devrait effectuer SQLITE ?

    ou alors existe t'il un moyen de mieux protéger le code avec la librairie Sqlite ?

    Cdt,
    Bonjour,

    oui, c'est bien des verrous mais appelés avec la librairie de SQLite.
    Je te conseille surtout de parcourir la doc SQLite il y a une mine d'information sur des fonctions : http://www.sqlite.org/c3ref/funclist.html
    Bon, je sais, tu l'as déjà fait, sinon tu n'aurais pas fait ce code. Mais recommence, il y a peut-être de idées à récupérer (il y a aussi les forums en anglais et le suivi des bugs http://www.sqlite.org/cvstrac/index).

    En voici une (l'utilises-tu ?)

    int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);

    => permet de déclarer l'adresse d'un handler qui sera appelé lorsqu'un accès à une table répond SQLITE_BUSY ou SQLITE_IOERR_BLOCKED.


    Sinon, si ta question est : dois-je gérer moi même des verrous ? la réponse est non : tu prépares et traites ta requête normalement, mais si SQLite répond SQLITE_BUSY, alors tu dois gérer les attentes et retenter ta chance plus tard. Tu ne dois pas te substituer à SQLite dans les tâches IO, c'est lui qui pose les verrous.

    Si malgré tout, tu n'arrives pas à régler ton problème, c'est que tu arrives aux limite du produit actuel. Dans ce cas, isole bien le bug afin de pouvoir le reproduire à coup sur et soumet-le au forum anglais si tu penses que l'erreur ne vient pas de ton code.

    a+

  7. #7
    Membre averti
    Inscrit en
    Décembre 2007
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 16
    Par défaut
    Merci Bigane de la rapidité de tes réponses,

    donc après une soirée d'arrachage de cheveux j'ai vraisemblablement trouvé la base de mon problème :

    la taille d'allocation de ma requête SQL passée en paramètre dans la méthode sqlite3_prepare :

    la chaîne de caractères contenant la requête a une taille de 40 octets et j'allouais une taille de 100 Ko pour préparer la requête (c'est une taille par défaut que j'avais dans le code et qui me sert aussi pour faire des insertions (dans ce cas mes requêtes peuvent contenir un champ de données de 65 Ko).

    en mono process cela tournait avec des memory leaks à foison (mais j'en ai toujours, à inspecter donc) et ça causait des plantes lorsque deux process accédaient à la base :

    const int sizeSQL = 40 * sizeof(char) + 1; (et non plus 100000)
    char *p_sql = 0

    ouverture base

    p_sql = sqlite3_printf("Select mon truc dans chose où x=y", blablabla);
    rc = sqlite3_prepare(db, p_sql, sizeSQL, p_stmt, NULL);

    lecture des données (boucle tant que SQLITE_BUSY)

    sqlite3_free(p_sql);
    sqlite3_finalize(p_stmt);

    fermeture base

    => le code est il ainsi suffisamment blindé, et cela génère t'il encore des fuites mémoires ?

    Merci pour la fonction busy_handler, je regarde cela dès que possible

Discussions similaires

  1. Lenteur et crashs dans Firefox
    Par gradubide dans le forum Firefox
    Réponses: 0
    Dernier message: 04/04/2008, 16h06
  2. crash dans CSimpleString<char,1>::CloneData()
    Par philippe V dans le forum Visual C++
    Réponses: 3
    Dernier message: 06/11/2007, 08h30
  3. crash dans MSVCRTD!fcloseall ?
    Par tsoueid dans le forum Visual C++
    Réponses: 2
    Dernier message: 29/10/2007, 06h52
  4. "gnome-keyboard-properties" crash dans Debian
    Par 00700 dans le forum Debian
    Réponses: 0
    Dernier message: 07/10/2007, 18h07
  5. attraper un crash dans une fonction d'une bibliothèque
    Par JeromeCJU dans le forum Bibliothèques
    Réponses: 5
    Dernier message: 10/03/2006, 13h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo