Wenn Ihre Datenbank klein genug ist, können Sie das Dateisystem verwenden. Der Vorteil dieses Ansatzes besteht darin, dass er sehr technisch ist und überall mit sehr wenig Code funktioniert. Wenn die Schlüssel aus druckbaren Zeichen bestehen und keine enthalten /
, können Sie sie als Dateinamen verwenden:
put () { key=$1; value=$2; printf %s "$value" >"datastore.db/$key"; }
get () { key=$1; cat "datastore.db/$key"; }
remove () { key=$1; rm "datastore.db/$key"; }
Um beliebige Schlüssel aufzunehmen, verwenden Sie eine Prüfsumme des Schlüssels als Dateinamen und speichern optional eine Kopie des Schlüssels (es sei denn, Sie können die Schlüssel nicht auflisten oder den Schlüssel für einen bestimmten Eintrag angeben).
put () {
key=$1; value=$2; set $(printf %s "$key" | sha1sum); sum=$1
printf %s "$key" >"datastore.db/$sum.key"
printf %s "$value" >"datastore.db/$sum.value"
}
get () {
key=$1; set $(printf %s "$key" | sha1sum); sum=$1
cat "datastore.db/$1.value"
}
remove () {
key=$1; set $(printf %s "$key" | sha1sum); sum=$1
rm "datastore.db/$1.key" "datastore.db/$1.value"
}
Beachten Sie, dass die obigen Spielzeugimplementierungen nicht die ganze Geschichte darstellen: Sie haben keine nützlichen Transaktionseigenschaften wie Atomizität. Die grundlegenden Dateisystemoperationen wie das Erstellen und Umbenennen von Dateien sind jedoch atomar und es ist möglich, atomare Versionen der obigen Funktionen zu erstellen.
Diese Direkt-zu-Dateisystem-Implementierungen eignen sich mit typischen Dateisystemen nur für kleine Datenbanken mit bis zu einigen tausend Dateien. Darüber hinaus haben die meisten Dateisysteme Schwierigkeiten, mit großen Verzeichnissen umzugehen. Sie können das Schema an größere Datenbanken anpassen, indem Sie ein mehrschichtiges Layout verwenden. Anstatt beispielsweise alle Dateien in einem Verzeichnis zu speichern, speichern Sie sie in separaten Unterverzeichnissen, basierend auf den ersten Zeichen ihres Namens. Dies ist zum Beispiel die Aufgabe von git : Die durch SHA-1-Hashes indizierten Objekte werden in Dateien mit dem Namen gespeichert .git/objects/01/2345679abcdef0123456789abcdef01234567
. Andere Beispiele für Programme, die eine semantische Schichtung verwenden, sind die Web-Caching-Proxys Wwwoffle und polipo ; Beide speichern die zwischengespeicherte Kopie einer Seite, die unter einer URL gefunden wurde, in einer Datei mit dem Namenwww.example.com/HASH
wobei HASH eine Codierung eines Hash der URL ist.¹
Eine weitere Ursache für Ineffizienz ist, dass die meisten Dateisysteme beim Speichern kleiner Dateien viel Speicherplatz verschwenden. Auf typischen Dateisystemen wird unabhängig von der Größe der Datei eine Verschwendung von bis zu 2 KB pro Datei verursacht.
Wenn Sie sich für eine echte Datenbank entscheiden, müssen Sie nicht auf den Komfort eines transparenten Dateisystemzugriffs verzichten. Es gibt verschiedene FUSE- Dateisysteme für den Zugriff auf Datenbanken, darunter Berkeley DB (mit Jeff Garziks Datenbank ), Oracle (mit Oracle DBFS ), MySQL (mit mysqlfs ) usw.
¹
Bei einer URL wie der von http://unix.stackexchange.com/questions/21943/standard-key-value-datastore-for-unix
Polipo wird die Datei unix.stackexchange.com/M0pPbpRufiErf4DLFcWlhw==
mit einem zusätzlichen Header in der Datei verwendet, der die tatsächliche URL in Klartext angibt. Der Dateiname ist die Base64-Codierung des MD5-Hash (in Binärform) der URL. Wwwoffle benutzt die Datei http/unix.stackexchange.com/DM0pPbpRufiErf4DLFcWlhw
; Der Name der Datei ist eine selbst erstellte Codierung des MD5-Hashs, und eine Begleitdatei http/unix.stackexchange.com/UM0pPbpRufiErf4DLFcWlhw
enthält die URL.