Armazenamento de dados de chave / valor padrão para o unix

15

Eu sei sobre as bibliotecas chave / valor para o unix ( berkeleydb , gdbm , redis ... ). Mas antes de começar a programar, gostaria de saber se existe uma ferramenta padrão para o UNIX que me permita executar as seguintes operações:

$ 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...

Obrigado

    
por Pierre 03.10.2011 / 14:42

4 respostas

9

Eu não acho que existe uma ferramenta padrão para isso. Exceto para grep / awk / sed etc. Mas usando isso, você precisará se preocupar com muitos outros problemas como bloqueio, formatação, caracteres especiais, etc.

Sugiro usar sqlite . Defina uma tabela simples e, em seguida, crie as funções tool_get() e tool_put() shell. sqlite é portátil, rápido.

Você terá flexibilidade extra gratuitamente. Você pode definir restrições, indexar para ajustar seu script ou usar esse banco de dados em outros idiomas algum dia.

    
por 03.10.2011 / 15:38
8

Se o seu banco de dados for pequeno o suficiente, você poderá usar o sistema de arquivos. A vantagem dessa abordagem é que ela é de baixa tecnologia e funciona em todos os lugares com muito pouco código. Se as chaves forem compostas de caracteres imprimíveis e não contiverem / , você poderá usá-las como nomes de arquivos:

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"; }

Para acomodar chaves arbitrárias, use uma soma de verificação da chave como nome do arquivo e, opcionalmente, armazene uma cópia da chave (a menos que você esteja satisfeito em não poder listar as chaves ou dizer qual é a chave para uma determinada entrada).

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"
}

Observe que as implementações de brinquedos acima não são a história completa: elas não têm nenhuma propriedade transacional útil , como atomicidade . As operações básicas do sistema de arquivos, como criação e renomeação de arquivos, são atômicas, e é possível construir versões atômicas das funções acima.

Essas implementações diretas para o sistema de arquivos são adequadas para sistemas de arquivos típicos apenas para bancos de dados pequenos, até alguns milhares de arquivos. Além desse ponto, a maioria dos sistemas de arquivos tem dificuldade em lidar com grandes diretórios. Você pode adaptar o esquema a bancos de dados maiores usando um layout em camadas. Por exemplo, em vez de armazenar todos os arquivos em um diretório, armazene-os em subdiretórios separados com base nos primeiros caracteres de seus nomes. Isto é o que o git faz, por exemplo: seus objetos, indexados por hashes SHA-1, são armazenados em arquivos chamados .git/objects/01/2345679abcdef0123456789abcdef01234567 . Outros exemplos de programas que usam camadas semânticas são os proxies de cache da web Wwwoffle e polipo ; ambos armazenam a cópia em cache de uma página encontrada em uma URL em um arquivo chamado www.example.com/HASH , em que HASH é alguma codificação de algum hash da URL.¹

Outra fonte de ineficiência é que a maioria dos sistemas de arquivos desperdiça muito espaço ao armazenar arquivos pequenos - há um desperdício de até 2kB por arquivo em sistemas de arquivos típicos, independentemente do tamanho do arquivo.

Se você optar por um banco de dados real, não precisará renunciar à conveniência do acesso transparente ao sistema de arquivos. Existem vários sistemas de arquivos FUSE para acessar bancos de dados incluindo o Berkeley DB (com fuse-dbfs ), MySQL (com mysqlfs ), etc.

Para um URL como http://unix.stackexchange.com/questions/21943/standard-key-value-datastore-for-unix , Polipo usa o arquivo unix.stackexchange.com/M0pPbpRufiErf4DLFcWlhw== , com um cabeçalho adicionado dentro do arquivo indicando o URL real em texto não criptografado; o nome do arquivo é a codificação base64 do hash MD5 (em binário) da URL. Wwwoffle usa o arquivo http/unix.stackexchange.com/DM0pPbpRufiErf4DLFcWlhw ; o nome do arquivo é uma codificação caseira do hash MD5 e um arquivo complementar http/unix.stackexchange.com/UM0pPbpRufiErf4DLFcWlhw contém o URL.

    
por 03.10.2011 / 23:55
7

dbmutil pode conseguir o que você deseja. Tem utilitários de shell para as operações que você descreve na questão. Eu não diria que é exatamente o padrão, mas tem as instalações que você quer.

    
por 03.10.2011 / 15:45
5

Desde que você o nomeou, o cliente padrão redis possui uma interface de linha de comando através de redis-cli . Alguns exemplos de redis-cli -h :

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

(E se você quiser acessar o banco de dados através do sistema de arquivos, você pode usar sockets com -s . Uma ferramenta que leia o índice db diretamente em cada chamada seria bastante ineficiente.)

    
por 03.10.2011 / 16:08

Tags