2010-11-04 8 views
6

J'ai une application multithread qui utilise SQLite (3.7.3)Éviter la base de données sqlite3 verrouillé

je frappe la base de données erreur verrouillé qui semble être assez répandue. Je me demande comment l'éviter dans mon cas.

Permettez-moi de décrire ce que je construis. Désolé, aucun code n'est trop grand et complexe.

J'ai environ 8 threads qui accèdent simultanément à la base de données. N'importe lequel de ces threads peut lire ou écrire en même temps.

Chaque ligne d'une table de la base de données possède un chemin de fichier qui pointe vers une ressource + d'autres attributs associés à cette ressource.

3 champs de note sont les lecteurs, statut et del.

lecteurs est incrémentée chaque fois qu'un thread lit de la ressource, mais seulement si l'état> 0 et del = 0.

j'ai donc un SQL qui ne

UPDATE resource set readers=readers+1 where id=? AND del=0 AND status>0 

Après cela, je vérifie le nombre de lignes mises à jour. Il devrait seulement être 1. Après cela, j'essaie de lire la ligne arrière avec un select. Je fais cela même s'il a échoué pour mettre à jour parce que j'ai besoin de savoir la raison pour laquelle il a échoué.

J'ai essayé d'envelopper à la fois la mise à jour et la sélection dans une transaction, mais cela n'a pas aidé. J'ai vérifié que j'appelais finaliser sur mes relevés aussi.

Maintenant, je pensais que sqlite sérialisait par défaut. J'ai essayé quelques modes ouverts mais j'ai toujours la même erreur.

Et avant de demander, non je n'ai pas l'intention d'aller à mysql. J'ai absolument besoin de zéro config. Est-ce que quelqu'un peut fournir quelques indications sur la façon d'éviter ce type de problème? devrais-je déplacer le verrouillage des lecteurs de la DB? Si je fais cela, quel mécanisme devrais-je remplacer? J'utilise Linux sous C++ et avec la bibliothèque de boost disponible.

EDIT: Il est intéressant de noter que l'ajout de COMMIT après l'appel mis à jour a considérablement amélioré les choses.

+1

La validation plus fréquente permet des verrous EXCLUSIF plus granulaires sur le fichier de base de données, ce qui réduit le temps que les lecteurs passent à attendre sur la table pour être déverrouillés. Cela se fait au détriment de l'augmentation du coût des fichiers journaux. Consultez http://sqlite.org/lockingv3.html#writing pour plus d'informations. – checker

Répondre

1

Lorsque vous ouvrez le db, vous devez configurer le « délai d'attente occupé »

int sqlite3_busy_timeout(sqlite3*, int ms); 

http://www.sqlite.org/c3ref/busy_timeout.html

+2

Salut, oui j'ai essayé ça. Ça aide un peu. Mais même lorsqu'il est réglé sur 1 seconde, il se heurte toujours au problème de verrouillage. J'ai activé le mode shared_cache et cela semble aider plus qu'un timeout occupé. Je vais essayer les deux. – Matt

+0

Il s'avère que sqlite était juste trop martelé pour mon application. J'ai donc déplacé le champ des lecteurs en mémoire à la place. Cela a amélioré la performance d'environ 10000% et je frappe le disque dur moins. – Matt

1

Première question: vous essayez d'utiliser une connexion avec tous les huit fils? Si c'est le cas, assurez-vous que chaque thread a sa propre connexion. Je ne connais aucune base de données qui aime ça.

Vérifiez également la FAQ: http://www.sqlite.org/faq.html

Apparemment, SQLite doit être compilé avec une option de préprocesseur SQLITE_THREADSAFE à 1. Ils ont une méthode pour déterminer si c'est votre problème.

Un autre problème est que les écritures ne peuvent se produire que d'un seul processus en toute sécurité.

+0

Oui, une connexion par thread. Je vais vérifier l'option de préprocesseur threadsafe. J'étais sous l'impression que c'était le défaut par contre. – Matt

+0

Comment je définis cette option? – ademar111190

Questions connexes