ChickenLipsRfun2eat
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
Hallo ihr Lieben! Vorab-Blala (optional:)
Ich nutze auf meinen Mobilgeräten (Handy, Netbook, Schleppi) einen kleinen selbstgebastelten Counter (zählt Kippen und Kaffee 😀), welcher seine Infos in einer SQLite-DB mit zwei Tabellen lokal speichert. Das Ganze würde ich nun gerne nach dem heimkommen im lokalen Netz mit dem Homeserver synchronisieren. Warum mit dem Homeserver? Nun, ich muss dann nicht immer alle Geräte anschalten, bzw. die synchronisieren sich dann eh alle von alleine, wenn ich im heimischen (W)LAN bin. Da das eine bidirektionale Synchronisierung ist, scheint mir das etwas schwieriger. Bei der Suche im Netz bin ich schon auf viele Dinge gestoßen, leider hauptsächlich fertige google-APIs, etc. für Android-Bastler. Das mag funktionieren, ich will es aber selbst basteln, da es an sich zu Lernzwecken dient. Ziel des Ganzen ist es, diese Mini-Anwendung als Plasmoid(plasma-widget), terminal-App mit DBUS und Sailfish-App zu schreiben, einfach damit ich ein wenig C++/QML/Qt/MySQL/SQLite/Python... lerne. Zum Thema
Ich brauche ein wenig Hilfe bei der Theorie zu o.g. "Problem". Mein momentaner Plan sieht so aus: Datenbank-Bibliothek, die auf allen Systemen eingesetzt werden kann. Pro System/Anwendung eine eigene Oberfläche, die lediglich den Aufsatz auf die Datenbank-Bib baut.
Die Datenbank-Bibliothek muss also zunächst alles brav lokal speichern, was an sich kein Problem darstellt. Zusätzlich möchte ich eine Synchronisierungsfunktion basteln, die bei Bedarf (oder per Dispatcher ausgelöst) die offline- und online-Datenbank abgleicht. Die Theorie dazu sieht derzeit so aus:
Auf dem mobil-Gerät: Timestamp der letzten Synchronisierung in der lokalen DB/config file abspeichern Alle Einträge seit der letzten Synchronisierung auslesen und in einer SQLdump oder einem eigenen Format speichern. Die Datei zum Server übertragen
Auf dem Server: Die empfangene Datei prüfen (passiert zwar nix, gehört aber dazu ☺) Die eigenen Einträge seit dem ersten timestamp ebenfalls in ein von mir weiterzuverarbeitendes Format exportieren Diese Datei an das mobil-Gerät senden. Empfangene Daten in die "online-DB" eintragen.
Die Theorie hat aber nen mega Haken. Wenn ich einen Eintrag lokal ändere, der zeitlich VOR dem sync-timestamp liegt, bleibt diese Änderung nur lokal. Jedesmal die ganze Datenbank zu übertragen mag zwar in meinem Fall keine Probleme verursachen, da sie seeehr klein ist, aber es geht ja eher ums Verständnis und "mal gemacht haben". Die könnte auch ein GiB groß sein und über mobile Daten laufen... Daher bitte ich um Vorschläge, wie man sowas sinnvoller angehen kann, ohne zuviel von der Umsetzung zu verraten ☺ Eine weitere Idee wäre lokal eine "Puffertabelle" zu verwenden, in der neue Einträge und Änderungen an alten gespeichert werden. Diese würde dann zum Server und anschliessend in die eigentliche Tabelle übertragen werden. Das wäre allerdings nen immenser Aufwand. Da wäre es - zumindest bei meiner kleinen Anforderung - wohl sinnvoller, ich würde eine bool-Spalte in die Tabelle bringen, die die Info enthält, ob der Eintrag synchronisiert werden muss oder nicht. Momentan steh ich da wie der Ochse vorm Berg und bitte um euer Gehirnschmalz ☺ Danke! /EDIT: Links für MySQL
|
senden9
Anmeldungsdatum: 8. Februar 2010
Beiträge: 965
Wohnort: Österreich
|
Was ich bezüglich Theorie noch einwerfen kann wäre der version vector. Die Liste „Other Mechanisms“ dort könnte dort auch noch Denkanstöße liefern. Offtopic: Ich glaub ich werde mir jetzt auch so etwas bauen. Allerdings mit Webinterface, REST-API und nur für Kaffee.
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Ein (üblicher) Ansatz in der DB wäre, in jeder Änderung auch den Timestamp der Änderung mit zu speichern/loggen. Dann hast Du einen sicheren und sauberen Anker, was seit der letzten Synchronisierung geändert wurde. (d.h. auch konkret, dass Du deinen Lokal-Dump anhand dieser Zeitstempel ziehst !) Zu dem DB-Handwerk habe ich zu wenig Ahnung, da muss wer anders 'ran. LG, track
|
ChickenLipsRfun2eat
(Themenstarter)
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
senden9 schrieb: Was ich bezüglich Theorie noch einwerfen kann wäre der version vector. Die Liste „Other Mechanisms“ könnte dort auch noch Denkanstöße liefern.
Würde bedeuten, ich vergleiche zunächst nur die ID und den Versionszähler der gesamten Tabellen von DB1 und DB2 und muss danach die höherwertigen der jeweiligen Datenbank auslesen und in die jeweils andere Datenbank eintragen. Das ist schonmal nen Ansatz. Danke!!!
Offtopic: Ich glaub ich werde mir jetzt auch so etwas bauen. Allerdings mit Webinterface, REST-API und nur für Kaffee.
Mach das. Ist schon erstaunlich, was da im Monat an Geld weggeht... allein für Kaffee. (Den zu hause berechne ich mit 25ct., den gekauften mit 2€).
|
ChickenLipsRfun2eat
(Themenstarter)
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
track schrieb: Ein (üblicher) Ansatz in der DB wäre, in jeder Änderung auch den Timestamp der Änderung mit zu speichern/loggen.
Ja. Wäre ein zweiter Timestamp, der aber mehr Aufwand beim Abfragen bringen würde. Zunächst prüfen, ob es einen "geändert"-Zeitstempel gibt (oder beim Eintragen gleich doppelt anlegen). Da gefällt mir sowas wie der Versionscounter besser, vor allem, weil der immer unter 10 bleiben wird. So oft ändert man ja nix in dem Fall.
Zu dem DB-Handwerk habe ich zu wenig Ahnung, da muss wer anders 'ran.
Das ist nicht so tragisch. Die Abfragen bekomme ich dann schon geschrieben. Wobei gerade MySQL so viele Werkzeuge bereit hält, dass ich da nicht wirklich ne Übersicht habe. Für die kleinen Tabellchen reicht es aber. Danke dir!
|
ChickenLipsRfun2eat
(Themenstarter)
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
Noch ein Haken bei der Sache: MySQL hat bekanntermaßen eine klare und messbare Struktur (int, unsigned int,...), SQLITE3 nicht. Da kann ein Eintrag als tinyint definiert sein aber auch nen blob enthalten. Muss ich das programmiertechnisch ebenfalls berücksichtigen? (in meinem Fall natürlich nicht. Total übertrieben. Aber so liesse sich wohl recht leicht die MySQL-DB "infiltrieren"... Vllt sollte ich sqlite verdrängen^^
|
noisefloor
Ehemaliger
Anmeldungsdatum: 6. Juni 2006
Beiträge: 28326
Wohnort: WW
|
Hallo,
Da das eine bidirektionale Synchronisierung ist,
Was im allgemeinen als "Master-Master Replikation" bekannt ist. Wie du schon richtig erkannt hast, ist der trickreiche Part das Konfliktmanagement, was bei einer Master-Master Replikation zwingend ist. Das Konfliktmanagement sollte halt möglichst viel alleine Lösen können - aber auch wissen, wann es den Nutzer / Admin zum Handeln auffordern muss. Ein DB, die ein ziemlich ausgereiftes Konfliktmanagement hat, weil seit je her auf Master-Master Replikation ausgelegt, ist CouchDB und die API-Kompatible JavaScript Variante PouchDB. Wenn du das einsetzen würdest, brauchst du dir IMHO zumindest um die Replikationen kaum noch Gedanken machen. Wenn du unbedingt eine SQL-DB einsetzen willst wird's IMHO deutlich komplizierter. Gruß, noisefloor
|
ChickenLipsRfun2eat
(Themenstarter)
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
noisefloor schrieb: Ein DB, die ein ziemlich ausgereiftes Konfliktmanagement hat, weil seit je her auf Master-Master Replikation ausgelegt, ist CouchDB und die API-Kompatible JavaScript Variante PouchDB. Wenn du das einsetzen würdest, brauchst du dir IMHO zumindest um die Replikationen kaum noch Gedanken machen.
Wenn du unbedingt eine SQL-DB einsetzen willst wird's IMHO deutlich komplizierter.
Die CouchDB klingt echt interessant, wobei ich keine Ahnung von JavaScript habe, außer kleinere Teile in QML. Für meine Testanwendung da ist das aber etwas arg übertrieben, da ich sie ja auch auf jedem Klient installieren müsste. Wäre nun nichts schlimmes, aber ich arbeite am liebsten mit dem, was mitgeliefert wird. Daher kam ich auf sqlite3, bzw. MySQL. Ich überlege aber ernsthaft, ob ich meine Master-Master Replikation (danke für die Vokabel!) nicht insofern einfacher gestalte, als dass ich einfach für die paar einzutragenden Teile einen eigenen Datentyp schreibe und ganz auf eine Datenbank verzichte. Das Ganze könnte bspw. ein passenden JSON-Export enthalten, welchen ich dann auch in einer einzelnen CouchDB verwenden könnte. Die eigentliche Prüfung ist an sich nicht so schwer, da ich an sich nur int und double speichere und Text ausschließlich als Bezeichner verwende. Wenn ich beim Import alle nicht erwünschten Sonderzeichen herausfiltere, die auch beim Erstellen auf dem Endgerät als nicht verwendbar einstellbar sind, sollte es sicher sein. Zudem ist das eine Übung, um in die Materie reinzukommen. Man wird von so vielen Dingen erschlagen, dass ich kleiner anfangen sollte und mich nicht gleich übernehme ☺ Danke für dein Feedback!
|
noisefloor
Ehemaliger
Anmeldungsdatum: 6. Juni 2006
Beiträge: 28326
Wohnort: WW
|
Hallo, so eine ähnliche Idee hatte ich auch, als ich nach dem Post noch ein wenig darüber nachgedacht habe. Eigentlich ist die Datenstruktur so simpel, dass jede Art von DB eigentlich übertrieben ist. JSON wäre vielleicht ein gute Alternative. Gruß, noisefloor
|
ChickenLipsRfun2eat
(Themenstarter)
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
Hier mal ein Vorschlag, wie die interne Struktur aussehen könnte: Zwei Datentypen zum Speichern:
Die Allgemeine Tabelle Die Datentabelle:
Der Aufbau der allgemeinen Tabelle wäre dann:
ID|strName|strValue Beispiel:
1|Einheit|Stück
2|Einheit|Liter
3|deleted|deleted
4|item|Zigaretten
5|item|Milchkaffee
6|item|Automatenkaffee Der Aufbau der Datentabelle:
ID|timestamp|itemNumber|einheitNumber|valueDouble|updateCounter Beispiel:
1|now|4|1|0.25|0 Würde bedeuten, ich brauche eigene Befehle für
insert (neuer Eintrag), update (Bearbeiten eines Eintrages, inklusive hochsetzen des updateCounters), delete (löschen von Doppelbuchungen,etc.), select Auswahl, beziehungsweise Summe der gültigen Einträge im angegebenen Zeitraum, da ich keine Mengen buche, sondern jeder Eintrag eine 1 ist. Optional: Mengenfeld mit Standard 1), inklusive umgesetzte WHERE Klausel, für Einschränkungen nach Zeit, Artikel, Einheit, etc.
Habe ich was vergessen / übersehen?
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12534
|
Nur um mal noch einen anderen Ansatz ins Spiel zu bringen: git hat ja auch ausgeklügelte Methoden, Änderungen zu verfolgen und Konflikte bei parallelen Updates an mehreren Orten zu mergen. Ich weiß jetzt nicht, was Deine Datenstrukturen sind, aber nehmen wir mal an, Du kannst alles in einzelnen JSON-Dokumenten speichern und es sind nicht so viele, dass das Dateisystem wegen zu vielen Dateien in einem Verzeichnis Ärger macht. Dann könntest Du alle diese Dokumente in ein Verzeichnis packen und mit git verwalten. Dann musst Du "nur" noch einen Weg finden, die Konfliktauflösung zu realisieren. Da das in Deinem Fall Zähler sind, müsste ein Dreiwege-Merge so aussehen, dass Du den Zählerstand auf z0 + (z1 - z0) + (z2 - z0) = z1 + z2 - z0 setzt. git würde Dir dann die Dateien mit Konflikten liefern und Du müsstest die manuell verarbeiten. noisefloor schrieb:
Ein DB, die ein ziemlich ausgereiftes Konfliktmanagement hat, weil seit je her auf Master-Master Replikation ausgelegt, ist CouchDB und die API-Kompatible JavaScript Variante PouchDB. Wenn du das einsetzen würdest, brauchst du dir IMHO zumindest um die Replikationen kaum noch Gedanken machen.
Ist das wirklich so? Wenn ich mich recht erinnere, dann speichert CouchDB JSON-Dokumente. Replikation funktioniert so lange automatisch, wie es keine Konflikte gibt. Wenn ein Konflikt auftritt, erkennt das die DB natürlich. Aber in dem Fall muss man sich beide (oder sogar mehrere) Versionen eines Dokuments von der DB geben lassen, sie "irgendwie" mergen und dann festlegen, was der aktuelle Stand sein soll.
Wenn du unbedingt eine SQL-DB einsetzen willst wird's IMHO deutlich komplizierter.
Jau. Es gibt da etwas für PostgreSQL, aber das ist noch kein Serienfeature. Und auch da muss man die Konfliktauflösung selbst machen, weil das einfach kein automatisches System entscheiden kann. Dazu braucht es Wissen über die Natur der Daten und deren Verwendung.
|
noisefloor
Ehemaliger
Anmeldungsdatum: 6. Juni 2006
Beiträge: 28326
Wohnort: WW
|
Hallo,
Ist das wirklich so? Wenn ich mich recht erinnere, dann speichert CouchDB JSON-Dokumente. Replikation funktioniert so lange automatisch, wie es keine Konflikte gibt.
Korrekt.
Wenn ein Konflikt auftritt, erkennt das die DB natürlich.
Korrekt.
Aber in dem Fall muss man sich beide (oder sogar mehrere) Versionen eines Dokuments von der DB geben lassen, sie "irgendwie" mergen und dann festlegen, was der aktuelle Stand sein soll.
Auch richtig. Wie ich ja auch schrieb: es gibt kein Konfliktmanagement, was garantiert ohne Nutzer-Interaktion auskommt. Wenn du Dokument im FooBarverschiedenen Änderungen auf verschiedenen Rechner machst, dann musst du ggf. beim nächsten Sync manuell eingreifen. Das ist bei Git oder allen anderen DVCS ja auch so. Gruß, noisefloor
|
ChickenLipsRfun2eat
(Themenstarter)
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
Mein Konfliktmanagement wäre ja bei doppelter ID auf die updateCounter zurückzugreifen und den höheren Wert als gültig zu nehmen und damit den Eintrag abzuändern.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12534
|
ChickenLipsRfun2eat schrieb: Mein Konfliktmanagement wäre ja bei doppelter ID auf die updateCounter zurückzugreifen und den höheren Wert als gültig zu nehmen und damit den Eintrag abzuändern.
Das würde aber nicht die korrekte Zählung wiedergeben, oder? (siehe meine Berechnung weiter oben)
|
ChickenLipsRfun2eat
(Themenstarter)
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
rklm schrieb: Das würde aber nicht die korrekte Zählung wiedergeben, oder? (siehe meine Berechnung weiter oben)
Meinst du die Zählung der Änderungen? Ein "Menge"-Feld gibt es ja so gesehen nicht, weil jede Buchung die Menge 1 darstellt. Beispiel:
Rechner1 bucht. Zähler 0. Rechner2 übernimmt, da die ID fehlt. Zähler noch 0. Rechner3 übernimmt, ändert, dadurch Zähler 1. Rechner1&2 übernimmt, Zähler 1. usw.
Falls ich auf zwei Rechnern den selben Wert auf verschiedene Daten ändere, wäre das aber ein Konflikt, der nicht abgedeckt würde, da durch den dann gleichen Zähler gnadenlos das zuerst synchronisierte Gerät den Zähler auf den Änderungswert setzt und der dritte Rechner mit der zweiten Änderung so tut, als wäre es schon abgeglichen. Dann wäre der Eintrag eines Zeitstempels ratsam, wie track vorschlug. Da es sich um keine Mehrbenutzer-Umgebung handelt, sondern nur einen Benutzer, der halt je ein anderes Gerät rumschleppt, wäre das wohl in meinem Fall vernachlässigbar, aber die sicherere Lösung. Aktuellster Änderungsstempel hätte dann jeweils Vorrang.
|