Wednesday, October 15, 2008

Cache de DataSets em aplicações multi-camadas

Há algum tempo utilizo mecanismos diversos de cache para melhorar a performance das aplicações que desenvolvo, principalmente com relação a acesso a bancos de dados. De uma forma mais aplicada venho desenvolvendo um mecanismo genérico de cache, para ser utilizado em aplicações multi-camadas. Problemas simples como o do post anterior (campos de lookup) podem ser muito beneficiados com mecanismo deste tipo.

É interessante ver que a maioria das aplicações mais "avançadas" ou elaboradas possuem algum mecanismo de cache mas no "mundo real" das aplicações comerciais que possuem acesso pesado a bancos de dados, o uso de um mecanismo de cache, por mais precário que seja, é raro ou inexistente.
O Delphi tem, out of the box, tudo que é necessário para fazer um cache nem tão rudimentar assim. Na verdade, depois de pronto, acho que poderia bater em muita coisa comercial que tem por aí... O ClientDataSet é um candidato perfeito para ser um DataSet genérico utilizado em um cache: é um DataSet em memória, pode ser gravado em disco em formato nativo (binário) e está presente na maioria das aplicações multi-camadas escritas em Delphi.

De forma geral e bem simplificada, o cache deveria funcionar da seguinte forma:
- Um DataSet é requerido à aplicação servidora (middle-tier) pela aplicação cliente;
- O mecanismo de cache (iremos chamá-lo de "gerenciador do cache") verifica se este DataSet já está no cache. Caso não esteja, a consulta normal ao banco de dados é efetuada. Caso o DataSet exista no cache, o gerenciador do cache deverá determinar se o cache está atualizado. Se estiver, o DataSet no cache é retornado à aplicação cliente sem necessidade de acesso ao banco de dados. Se não estiver, a consulta normal ao banco de dados é efetuada;
- Caso a consulta normal ao banco seja efetuada (o DataSet não está no cache ou o mesmo se encontra desatualizado) o gerenciador do cache se encarrega de incluir/atualizar o cache com este DataSet recém obtido do banco de dados;
- O gerenciador do cache deve prever acessos simultâneos de diferentes threads;
- O gerenciador do cache deve persistir e recuperar o cache em um repositório local (disco).

Simples não? Bem... não é tão simples mas também não é ciência de foguetes. Veremos que existem vários requisitos que deverão ser satisfeitos para que o mecanismo de cache seja viável. Entre eles, podemos citar:

1) O gerenciador do cache deverá ser capaz de identificar unicamente um DataSet;
2) O gerenciador do cache deverá ser capaz de identificar de forma inequívoca se o cache reflete a situação atual do banco de dados, ou seja, se o cache está atualizado no que tange àquele DataSet específico.

O requisito número 1 exige que o banco de dados se adapte à aplicação, ou seja, ao uso do cache. Os sistemas que desenvolvo já possuíam uma estrutura adequada, mesmo antes de um mecanismo de cache ser pensado. Então neste caso foi fácil.

Irei detalhar como satisfazer os requisitos 1 e 2 no próximo post.

No comments: