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

16

Eu sei sobre as bibliotecas de chave / valor para unix ( berkeleydb , gdbm , redis ...). Mas antes de começar a codificar, pergunto-me se existe uma ferramenta padrão para 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

Pierre
fonte

Respostas:

10

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

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

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

Michał Šrajer
fonte
Obrigado . Eu rapidamente escrevi uma ferramenta com a API sqlite. Funciona bem.
313 Pierre
9

Se 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 funcionará em qualquer lugar com muito pouco código. Se as chaves forem compostas por caracteres imprimíveis e não contiverem /, você poderá usá-las como nomes de arquivo:

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 o nome do arquivo e, opcionalmente, armazene uma cópia da chave (a menos que você esteja feliz por 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 toda: elas não têm nenhuma propriedade transacional útil , como atomicidade. Entretanto, as operações básicas do sistema de arquivos, como criação e renomeação de arquivos, são atômicas e é possível criar versões atômicas das funções acima.

Essas implementações diretas ao 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 diretórios grandes. 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. É isso 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 uma estratificação semântica são a web cache proxies Wwwoffle e polipo ; ambos armazenam a cópia em cache de uma página encontrada em uma URL em um arquivo chamadowww.example.com/HASH onde HASH é uma codificação de algum hash da URL.¹

Outra fonte de ineficiência é que a maioria dos sistemas de arquivos gasta 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 usar um banco de dados real, não precisará abrir mão da conveniência do acesso transparente ao sistema de arquivos. Existem vários sistemas de arquivos FUSE para acessar bancos de dados, incluindo Berkeley DB (com dbfs de Jeff Garzik ), Oracle (com Oracle DBFS ), MySQL (com mysqlfs ), etc.

¹ Para uma 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 a 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 doméstica do hash MD5 e um arquivo complementar http/unix.stackexchange.com/UM0pPbpRufiErf4DLFcWlhwcontém o URL.

Gilles 'SO- parar de ser mau'
fonte
7

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

ConcernedOfTunbridgeWells
fonte
5

Desde que você o nomeou, o cliente redis padrão possui uma interface de linha de comando 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, poderá usar soquetes -s. Uma ferramenta que leria o índice db diretamente em cada chamada seria meio ineficiente.)

Stéphane Gimenez
fonte