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/UM0pPbpRufiErf4DLFcWlhw
contém o URL.