Se il tuo database è abbastanza piccolo, puoi usare il filesystem. Il vantaggio di questo approccio è che è molto a bassa tecnologia e funzionerà ovunque con pochissimo codice. Se le chiavi sono composte da caratteri stampabili e non contengono /
, è possibile utilizzarle come nomi di file:
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"; }
Per ospitare chiavi arbitrarie, utilizzare una somma di controllo della chiave come nome del file e, facoltativamente, archiviare una copia della chiave (a meno che non si sia soddisfatti di non essere in grado di elencare le chiavi o dire qual è la chiave per una determinata voce).
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"
}
Nota che le implementazioni di giocattoli sopra non sono l'intera storia: non hanno alcuna proprietà transazionale utile come l'atomicità. Le operazioni di base del filesystem come la creazione e la ridenominazione dei file sono tuttavia atomiche ed è possibile creare versioni atomiche delle funzioni precedenti.
Queste implementazioni dirette al filesystem sono adatte ai filesystem tipici solo per piccoli database, fino a qualche migliaio di file. Oltre a questo punto, la maggior parte dei filesystem ha difficoltà a gestire grandi directory. È possibile adattare lo schema a database più grandi utilizzando un layout a più livelli. Ad esempio, invece di archiviare tutti i file in una directory, archiviarli in sottodirectory separate in base ai primi caratteri dei loro nomi. Questo è ciò che fa git , ad esempio: i suoi oggetti, indicizzati dagli hash SHA-1, sono memorizzati in file chiamati .git/objects/01/2345679abcdef0123456789abcdef01234567
. Altri esempi di programmi che utilizzano una stratificazione semantica sono i proxy di cache Web Wwwoffle e polipo ; entrambi memorizzano la copia cache di una pagina trovata in un URL in un file chiamatowww.example.com/HASH
cui HASH è una codifica di alcuni hash dell'URL .¹
Un'altra fonte di inefficienza è che la maggior parte dei filesystem spreca molto spazio quando si archiviano file di piccole dimensioni: si spreca fino a 2kB per file su file system tipici, indipendentemente dalle dimensioni del file.
Se si sceglie di utilizzare un database reale, non è necessario rinunciare alla praticità dell'accesso al filesystem trasparente. Esistono diversi filesystem FUSE per accedere ai database tra cui Berkeley DB (con i dbfs di Jeff Garzik ), Oracle (con Oracle DBFS ), MySQL (con mysqlfs ), ecc.
¹
Per un URL come http://unix.stackexchange.com/questions/21943/standard-key-value-datastore-for-unix
, Polipo utilizza il file unix.stackexchange.com/M0pPbpRufiErf4DLFcWlhw==
, con un'intestazione aggiunta all'interno del file che indica l'URL effettivo in chiaro; il nome del file è la codifica base64 dell'hash MD5 (in binario) dell'URL. Wwwoffle utilizza il file http/unix.stackexchange.com/DM0pPbpRufiErf4DLFcWlhw
; il nome del file è una codifica home dell'hash MD5 e un file associato http/unix.stackexchange.com/UM0pPbpRufiErf4DLFcWlhw
contiene l'URL.