jStore - simpler Key/Value Store mit JSON backend

Code-Stücke können hier veröffentlicht werden.
Antworten
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Wenn man bei Änderungen der Daten nicht jedes Mal alles speichern will, bietet sich ein "append only"-Verfahren an, bei dem nur das Neue zu einer immer größer wachsenden Datei hinzugefügt wird. Wenn man sich nicht darauf verlassen will/kann, dass das Dateisystem transaktional ist, muss man aber wieder einigen Aufwand treiben. Auch das Einlesen der Daten wird aufwendiger. Und man ist immer noch auf den eigenen Hauptspeicher begrenzt. Kann mal alles noch relativ einfach bauen - oder etwas wie Redis benutzen.

Will man mehr speichern können, als in den Hauptspeicher passt, könnte man Index und Daten getrennt verwalten und hoffen, dass zumindest der Index in den Hauptspeicher passt. Nun gilt es aber beide Dateien zu sychronisieren bzw. beides wieder in eine "append only"-Datei zu stecken und etwas zu entwickeln, dass andere schon längst erfunden haben.

Wartet man noch etwas, kann Redis wohl auch virtuellen Speicher (auf Platte) effizient verwalten und alles wird gut. Oder man nutzt berkeleyDB oder ein vergleichbares System. Was anderes liegt letztlich auch nicht unter etwas wie Tokyo Tyrant drunter. Übrigens, größeres Kaliber wäre eine Document-DB wie Couch oder Mongo.

Noch einfacher ist es aber wahrscheinlich, einfach SQLite zu benutzen. Man definere sich eine Tabelle mit zwei Spalten: Key und Value und speichere als Werte gepickelte Python-Objekte. Möglicherweise ist eine einfachere Kodierung noch schneller. Weiß man etwa, dass man nur int, bool, str, bytes, list und dict in nicht-rekursiven Datenstrukturen ablegen können will, gibt es effiziente binäre Formate.

Dinge wie Tags oder eine Suchfunktion würde ich da oben drauf setzen. Hält man alles im Hauptspeicher, sind diese Dinge natürlich wieder trivial.

Die Trennung von Key und ID verwirrt mich übrigens. IMHO wäre die Eigenschaft des Keys, ein eindeutiger Schlüssel zu sein und jetzt noch einen zweiten Primärschüssel haben zu wollen finde ich komisch. Eine Indirektion mehr löst das Problem doch auch.

Stefan
monkey
User
Beiträge: 7
Registriert: Montag 22. März 2010, 16:56

Die Trennung von Key und ID verwirrt mich übrigens. IMHO wäre die Eigenschaft des Keys, ein eindeutiger Schlüssel zu sein und jetzt noch einen zweiten Primärschüssel haben zu wollen finde ich komisch. Eine Indirektion mehr löst das Problem doch auch.
Stimmt schon. Mein Ansatz ist, das wenn ich zum Beispiel User habe:

Code: Alles auswählen

    id    key            value
    --------------------------------------------------------------------
    1     u1@bla.de      { 'password' : '12345', 'realname' : 'U1 Bla' }
    2     u2@bla.com     { 'password' : '54321', 'realname' : 'U2 Bla' }
dann kann ich über die Mailadresse einfach auf den User zugreifen z.B bei einem Login, der aus einer Mail/Passwort Kombination besteht und zwar ohne im Value suchen zu müssen. Möchte ich diesen Usern aber dann noch Nachrichten zuordnen, kann ich das über die ID machen und es besteht die Option, den KEY jederzeit umzubenennen, ohne die Verbindung zu verlieren. Darüber hinaus kann ich die Daten über die ID sortieren was sonst nicht möglich wäre.

Ohne KEY müsste ich ja mindestens 2 Datensätze haben.

Code: Alles auswählen

    key            value
    --------------------------------------------------------------
    unic_key_1     { 'password' : '12345', 'realname' : 'U1 Bla' }
    unic_key_2     { 'password' : '54321', 'realname' : 'U2 Bla' }

    key            value
    ---------------------------
    u1@bla.de      'unic_key_1' 
    u2@bla.com     'unic_key_2'
Eines der Hauptprobleme meines Skripts ist ja Persistenz bzw. das Sperren einer Datei für weitere Zugriffe. Da das ganze nur unter Unix/Linux laufen soll, dachte ich, ich könnte das über Bordmittel regeln. Leider war das Ergebnis ziemlich ernüchternd. Ich habe sowohl "fcntl.lockf, fcntl.flock" als auch os.open mit O_EXLOCK/O_SHLOCK ausprobiert. Keine der beiden funktionierte auf meinem Ubuntu System. Dies liegt daran, dass Mandatory Locking im Standart Fall nicht aktiv ist. Dazu benötigt es einen Eintrag "mand" in der "/etc/fstab". Die Methode ist daher unbefriedigend weil das Skript ja auch mal auf einem Rechner laufen könnte, bei dem ich keinen Einfluss auf die Mount Optionen habe.

Das Konzept das Locking über Lockdateien zu realisieren erscheint mir daher gar nicht so abwegig, zumal ja auch andere z.B. Firefox einen solchen Mechanismus nutzen. Damit das Ganze auch dann noch funktioniert, wenn ein Prozess abstürzt, müsste es einen Timeout geben nach dem die Lockdatei auch von anderen Prozessen entfernt werden darf.

Da ja auch Lesezugriffe die Datei gegen Überschreibung sichern müssen, wären zwei verschiedene Lockarten sinnvoll. SharedLock und ExclusivLock.

Realisieren könnte man den SharedLock durch ein Verzeichnis in dem für jede PID eine Datei erstellt wird, die einen Timestamp und den Timeout enthält.

datei.txt
datei.txt.lock/
42342
98797
24377

Nachdem der Lock freigegeben wird, wird die PID-Datei entfernt. Sollte ein Prozess abstürzen, kann die Datei nach dem Timeout gelöscht werden.

Der ExclusivLock muss in dem Fall warten, bis alle Lesezugriffe beendet sind (hier sehe ich noch Schwierigkeiten aber dazu später mehr). Dieser erstellt nur eine einzige Datei, ebenfalls mit Timestamp und Timeout.

datei.txt
datei.txt.lock

Das Problem ist, dass der Schreibzugriff warten muss, bis alle SharedLocks beendet oder aufgeräumt wurden. In einem Szenario, wo es andauernde Lesezugriffe gibt, kann das natürlich ewig dauern. Besser währe daher eine Art Queue doch da gibt es dann das "Henne Ei" Problem da diese natürlich ebenfalls in irgendeiner Art gesperrt werden müsste. Andererseits wie realistisch ist es, das es so großen permanenten Zugriff gibt, dass die Datei ständig gelockt ist?

mokey
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

...oder du nimmst einfach Sqlite (siehe z.B. http://www.python-forum.de/post-165450.html#165450), denn dort hat jemand schon die ganze Locking-Problematik gelöst. Natürlich ginge auch ein externer KV-Store, doch Sqlite hat den Vorteil, eingebaut zu sein.

Stefan
Antworten