Uma abordagem consistente para sincronização de dados em diversos repositórios, com suporte melhorado para gestão de conflitos e concorrência, é a adoção de uma versão adaptada de Vector Clocks, uma estrutura de dados para sequenciamento de eventos, chamada Change Vectors.
Change Vector no RavenDB
Change Vector é a estrutura de dados adotada pelo RavenDB como fundamento para controlar gestão de dados sincronizados em bases de dados distribuídas, onde todos as instâncias operam como Master.
A lógica essencial é a seguinte:
- Todos os repositórios que irão armazenar dados sincronizados recebem um id único e imutável.
- Todas as tuplas para dados armazenados incluem um campo especial para o change vector.
- Quando uma nova tupla é criada, o campo dedicado ao change vector recebe uma entrada com a chave correspondendo ao id do repositório e um valor de contagens iniciado em 1.
- Toda vez que uma tupla é atualizada, o change vector tem o valor da entrada correspondente ao id do repositório incrementado em uma unidade.
Um mecanismo de sincronização pode usar, então, a informação do change vector para determinar qual versão da tupla é mais atualizada, executando a replicação.
As regras essenciais de comparação entre dois change vectors são:
- São iguais se, e somente se, todas as entradas, nos dois change vectors, tiverem valores iguais para todos os ids (ids não relacionados tem valor lógico zero)
- Um change vector A é maior que um change vector B se, e somente se, todos os valores forem maiores ou iguais entre os ids de repositório correspondentes.
- Um change vector A conflita com um change vector B se, e somente se, pelo menos um dos valores de A for maior ou igual ao correspondente B e pelo menos um dos valores de B for maior ou igual ao correspondente A.
Na ocorrência de um conflito, alguma estratégia de resolução precisa ser adotada, geralmente customizada pela natureza da própria tupla, geralmente, para isso, poderá ser recuperada a versão ancestral de todas as tuplas conflitantes, além da versão dessas tuplas.
As chances de conflitos reduzem bastante quando alterações em uma tupla acontecem preferencialmente em um único repositório, bem como, quando as comparações forem mais frequentes.
Eventualmente, os próprios repositórios podem manter change vectors globais para comparação rápida e determinar “sentido de atualização”