Autor Beitrag
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3897
Erhaltene Danke: 794

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Di 14.06.16 09:33 
Bei einem Projekt basierend auf Xamarin und SQLite unter iOS kommt es in letzter Zeit häufiger dazu, daß Daten in die Datenbank geschrieben werden, aber beim Auslesen nicht vorhanden sind. Hier schematisch der Code (intern mit SQLite.NET als ORM):
ausblenden C#-Quelltext
1:
2:
3:
int id = SaveData(data);

var data2 = ReadData(id);

Es wird auch jeweils eine korrekte (neue) Id zurückgegeben, und im Normalfall auch die Daten wieder erfolgreich gelesen.
Bei bestimmten Use-Cases aber (evtl. wenn andere Threads parallel schreibend/lesend auf die SQLite-DB zugreifen?) wird dann einfach null zurückgegeben (d.h. das Objekt wurde anhand der Id nicht gefunden).
Mittels Absicherungsmaßnahmen zum Verhindern einer Busy/Locked SQLiteException gibt es intern schon entsprechenden Code, welcher dann bis zu 100x versucht, die Daten (im Abstand von einigen Millisekunden) neu zu schreiben bzw. zu lesen (und dies wird auch protokolliert).
Aber selbst das passiert dann nicht, d.h. die Daten werden anscheinend korrekt in die DB gespeichert, aber können irgendwie nicht mehr ausgelesen werden (auch nicht nach einem Neustart der App).

Ich weiß, das sind nicht wirklich detailierte Infos, aber ich benötige auch eher Tipps bzw. Gedankenanregungen, wie ich den Fehler mehr auf die Spur kommen kann, um die eigentliche Ursache zu finden.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4345
Erhaltene Danke: 877


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 14.06.16 10:06 
Gibt es bei SQLite auf iOS das gleiche Problem mit den verschiedenen Builds? Also verschiedene Builds von SQLite mit und ohne Threadsafety bzw. Cross Thread Connection Sharing?
Th69 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3897
Erhaltene Danke: 794

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Di 14.06.16 10:17 
Ja, per se schon. Verwendet wird jedoch die vom iOS selbst installierte SQLite-Version.
Programmtechnisch verwende ich schon folgende Flags:
ausblenden C#-Quelltext
1:
SQLteConnection(GetDatabasePath(database), SQLiteOpenFlags.Create | SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.FullMutex)					

FullMutex entspricht dabei dem (Standard) Serialized-Mode von SQLite: SQLite And Multiple Threads.
Th69 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3897
Erhaltene Danke: 794

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Mi 15.06.16 10:54 
Hallo Ralf,

hast du denn noch eine andere Idee?

PS: Ich habe gestern bei dem Projekt noch einen anderen Bug hinterhergesucht: auf meinem Entwicklungsrechner lief es und beim Server-Build kam es bei den Testern zu Fehlern.
Heute habe ich rausgefunden, daß es wohl an einem der beiden Server lag, denn der Build des 2. ist wieder in Ordnung...
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4345
Erhaltene Danke: 877


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 15.06.16 11:14 
Nope.
Zuwenig Erfahrung mit SQLite. Die Erfahrung die ich gesammelt habe war das SQLite sobald Multithreading ins Spiel kommt, je nach Build, entweder kaputt ist oder zu langsam. Darum hab ich das frühzeitig wieder zur Seite gelegt.
Th69 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3897
Erhaltene Danke: 794

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Mi 15.06.16 12:16 
Danke, deine Einstellung bzgl. SQLite teile ich (mittlerweile). Ursprünglich war das C#-Projekt auch für MS SQL-Server entwickelt worden und dann gab es vor zwei Jahren den Schwenk nach iOS (bzw. bald wohl auch Android) - und da ist halt SQLite vorinstalliert...
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4345
Erhaltene Danke: 877


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 15.06.16 12:44 
Wenn das schreiben in die Datenbank gut isoliert ist kannst du mal probieren mit einem ReaderWriterLock Schreibvorgänge vollständig zu serialisieren.
Und dich danach fragen ob du mit der Performanceeinschränkung leben kannst wenn das hilft.


PS.
www.sqlite.org/c3ref...st_insert_rowid.html

Lies mal den letzten Absatz und frag dich ob das bei dir zutreffen könnte.
Benutzt du Connections Thread übergreifend?
Th69 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3897
Erhaltene Danke: 794

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Mi 15.06.16 14:03 
Nein, ich benutze immer nur kurzzeitige Connections (d.h. jeweils innerhalb eines Threads).

Stimmt, wir hatten schon mal bei der SQLiteException-Problematik mit lock herumgespielt, um das Schreiben zu serialisieren, aber uns dann für den FullMutex entschlossen (da wir keinen Vorteil darin gesehen und gemessen hatten).
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4345
Erhaltene Danke: 877


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 15.06.16 14:36 
lock wäre mir zuviel. Damit man ganz sicher ist müßte man ja auch lesen während dem schreiben verhindern (wenn man den Threading Möglichkeiten von SQLite nicht vertraut). Und das geht mit einem ReaderWriterLock besser als mit einem reinen lock. Bei einer schreibarmen Anwendung durchaus denkbar.
Th69 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3897
Erhaltene Danke: 794

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Mi 22.06.16 17:10 
Ich habe jetzt für eine Routine eine Lösung gefunden! Ich hatte in einer Schleife per Linq (und AutoMapper) Daten gelesen und wollte darauf dann den entsprechenden Datensatz in der DB aktualisieren (hatte dafür aber jeweils eine eigene Connection erzeugt).
Nun materialisiere ich vorher die gelesenen Daten und schreibe dann die Daten zurück - und danach kann ich auch diese geänderten Daten wieder auslesen.

Ich muß wohl demnächst (nach meinem Urlaub ;-)) den Code 'refactoren'...
Daher schließe ich diesen Beitrag.