Archivio dati chiave / valore standard per unix


16

Conosco la chiave / il valore librerie per unix ( berkeleydb , gdbm , redis ...). Ma prima di iniziare a scrivere codice, mi chiedo se esiste uno strumento standard per unix che mi consentirebbe di eseguire le seguenti operazioni:

$ tool -f datastore.db put "KEY" "VALUE"
$ tool -f datastore.db put -f file_key_values.txt
$ tool -f datastore.db get "KEY"
$ tool -f datastore.db get -f file_keys.txt
$ tool -f datastore.db remove "KEY"
$ etc...

Grazie

Risposte:


10

Non penso che ci sia uno strumento standard per quello. Eccetto pergrep / awk/ sedecc. Ma usando questo dovrai preoccuparti di molti altri problemi come il blocco, il formato, i caratteri speciali, ecc.

Suggerisco di usare sqlite. Definire una tabella semplice e quindi creare tool_get()etool_put() shell funzioni. sqliteè portatile, veloce.

Otterrai una flessibilità extra gratuitamente. Puoi definire vincoli, indicizzare per modificare il tuo script o utilizzare quel DB in altre lingue un giorno.


Grazie . Ho rapidamente scritto uno strumento con l'API sqlite. Funziona bene
Pierre,

9

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/UM0pPbpRufiErf4DLFcWlhwcontiene l'URL.


7

dbmutilpotrebbe darti quello che vuoi. Ha utilità di shell per le operazioni descritte nella domanda. Non direi che è esattamente standard, ma ha le strutture che desideri.


5

Da quando lo hai nominato, il client redis standard ha un'interfaccia a riga di comando redis-cli. Alcuni esempi da redis-cli -h:

 cat /etc/passwd | redis-cli -x set mypasswd
 redis-cli get mypasswd
 redis-cli -r 100 lpush mylist x

(E se vuoi accedere al db attraverso il filesystem puoi usare i socket con -s. Uno strumento che legge l'indice db direttamente su ogni invocazione sarebbe in qualche modo molto inefficiente.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.