Estou projetando um banco de dados de objetos na memória para um caso de uso muito específico. É um escritor único, mas deve suportar leituras simultâneas eficientes. As leituras devem ser isoladas. Não há linguagem de consulta, o banco de dados suporta apenas:
- obter objetos / s por atributo / conjunto de atributos (pode haver suporte para expressões, por exemplo
x.count < 5
) - obter atributo do objeto
Uma consulta é um script imperativo composto por um número arbitrário das operações acima. O tamanho dos dados será << memória; portanto, todos os objetos e índices na maioria dos atributos devem caber confortavelmente sem troca.
O que eu preciso é de uma estrutura de dados para o índice de atributo do objeto, que pode ser O (n) em gravações, não suporta simultaneidade de gravação, mas deve suportar idealmente O (1) instantâneos (talvez cópia na gravação) e acesso O (logN). Idealmente, isso permitiria alta simultaneidade nas leituras com o compartilhamento estrutural máximo entre as versões.
Eu estava olhando para CTries , BSTs simultâneos e árvores de exibição simultâneas, mas não tenho certeza se estou realmente olhando na direção certa aqui. As estruturas acima prestam muita atenção à complexidade das inserções com as quais não me importo.
A pergunta : existe uma estrutura de dados conhecida que seja adequada para o meu caso de uso imediatamente?
EDIT : depois de pensar um pouco mais, parece que uma árvore BST / Splay persistente funcionaria. O gravador atualizaria a cópia 'mestre' e as consultas obteriam a árvore a partir do início da execução e a jogariam fora depois que terminassem. No entanto, ainda estou interessado se houver uma solução melhor.
Respostas:
Use qualquer tipo de estrutura de dados baseada em árvore persistente / imutável (ou seja, funcional). A chave está acertando o bloqueio, como @Raphael apontou nos comentários.
O bom das estruturas de dados funcionais / persistentes baseadas em árvore é que você obtém "instantâneos" gratuitamente. Vamos supor que você use um treap (árvore de pesquisa binária aleatória) para sua estrutura de dados. Aqui está um exemplo de um escrito em Go: https://github.com/steveyen/gtreap . O autor descreve assim:
Você usa uma trava para proteger o ponteiro para a raiz. Como a estrutura de dados é imutável, as leituras podem ser feitas simultaneamente e você pode salvar os ponteiros em instantâneos antigos. Uma leitura é:
Mesmo que a pesquisa demore um pouco, você só mantém o bloqueio pressionado enquanto copia o ponteiro, para que as pesquisas possam ocorrer simultaneamente.
Uma gravação é:
Nesta versão, as gravações precisam manter o bloqueio durante todo o processo de criação da nova versão da árvore. Você pode melhorar o desempenho da leitura (às vezes, com a transação de gravação falhando) alterando a gravação para algo como isto:
Você poderá se sair um pouco melhor (torná-lo "travado") se sua linguagem de programação tiver variáveis atômicas com uma operação de comparação e troca atômica. (Por exemplo, usando C ++ 11.
atomic<T*>
)fonte
A Microsoft publicou detalhes sobre o novo banco de dados em memória, e possui índices que não bloqueiam as leituras enquanto as gravações estão sendo feitas.
Por exemplo:
Consulte http://research.microsoft.com/en-us/projects/main-memory_dbs/ para obter uma lista de suas publicações.
fonte