gestão de dados partilhados em ambientes de computação móvel

gestão de dados partilhados em ambientes de computação móvel gestão de dados partilhados em ambientes de computação móvel

asc.di.fct.unl.pt
from asc.di.fct.unl.pt More from this publisher
11.04.2013 Views

156 CAPÍTULO 10. SISTEMA DE RECONCILIAÇÃO SQLICECUBE criaUmaSolução ( bd, sumário, trxs) = // pseudo-código solução := [] valor := 0 REPEAT sumário.reinicia( trxs) WHILE sumário.algumaPossível() DO // Cria solução incrementalmente próxTrx := seleccionaPorMérito ( sumário) // Selecciona acção a executar dynOK := bd.executaInnerTrx( próxTrx) IF dynOK = FALSE THEN // Resultado: rollback sumário.excluiTmp( próxTrx) ELSE // Resultado: commit solução := [solução|próxTrx] // Actualiza solução valor := valor + próxTrx.valor sumário.executada( próxTrx) aExcluir := incompatíveis( próxTrx, trxs) // Actualiza informação sobre transacções sumário.exclui( aExcluir) aExcluirTmp := tornaImp( próxTrx) sumário.excluiTmp( aExcluirTmp) aIncluirTmp := tornaPosAjuda( próxTrx) sumário.incluiTmp( aIncluirTmp) END IF END WHILE gtrxs = gruposIncompletos(trxs,solução) // Transacções pertencentes a grupos indivísiveis trxs = trxs \ gtrxs // parcialmente executados IF( NOT vazio(gtrxs)) THEN bd.rollbackTrx() bd.initTrx() END IF UNTIL vazio(gtrxs) RETURN { solução, valor} Figura 10.3: Algoritmo de criação de uma única solução. Se a execução da transacção seleccionada aborta, a transacção passa a ser considerada temporaria- mente impossível de executar. Se uma transacção é executada com sucesso, ela é adicionada à solução parcialmente construída. A informação sobre as transacções a executar é actualizada. As transacções que são incompatíveis com a execução dessa transacção (relações alternativas e predecessor/sucessor fraco) são adicionadas ao conjunto das transacções impossíveis (assim como todas as transacções que perten- çam a um grupo indivisível com uma das transacções impossíveis). As transacções que são impossibili- tadas (relação impossibilita) são adicionadas ao conjunto das transacções temporariamente impossíveis. As transacções que são beneficiadas (relações torna possível e favorece) são removidas do conjunto das transacções temporariamente impossíveis. Em ambos os casos, o ciclo itera enquanto existem transac- ções candidatas com mérito não nulo. Quando se conclui a criação de uma solução é necessário verificar se a solução é válida face às relações estabelecidas 3 . Para tal, é necessário verificar se existe algum grupo indivisível parcialmente executado (todas as outras relações são necessariamente satisfeitas porque nunca se selecciona uma tran- sacção cuja execução viole uma relação estática com uma transacção anteriormente executada). Em 3 Uma optimização implementada no protótipo do sistema consiste na verificação, sempre que uma transacção é declarada impossível, da impossibilidade de executar completamente qualquer grupo indivisível com transacções já executadas. Neste caso, a solução que se está a criar é declarada imediatamente inválida.

10.3. ALGORITMO DE RECONCILIAÇÃO 157 reconciliaComPartições ( bd, trxs) = partições := particiona( trxs) // Divide em partições solução := [] valor := 0 FOR EACH part IN partições // Obtém solução para cada partição { soluçãoParcial, valorParcial } := reconcilia ( bd, part.trxs) solução := [ solução | soluçãoParcial ] valor := valor + valorParcial END FOR RETURN { solução, valor } Figura 10.4: Algoritmo de reconciliação (com partições). caso afirmativo, a solução é inválida e é necessário criar uma nova solução. Para evitar cair numa situ- ação semelhante na próxima solução criada, o grupo de transacções parcialmente executado é excluído (temporariamente) do conjunto de transacções a reconciliar. Apesar desta aproximação poder levar a uma solução sub-óptima, garante que é sempre possível obter uma solução (porque se vão excluindo os grupos de transacções que causam problemas). Durante a execução do algoritmo é criada uma explicação da razão pela qual cada transacção não foi incluída na solução final (omitido nos algoritmos apresentados). Esta informação pode ser usada pelas funções melhorSolução e termina ou para fornecer informação aos utilizadores. 10.3.3 Complexidade A complexidade temporal esperada da função criaUmaSolução é O(n 2 ), com n o número de transacções a reconciliar. Intuitivamente, o ciclo principal é executado O(n) vezes (O(n) transacções são seleccionadas para execução). A complexidade do ciclo principal é dominado pela função de selecção (seleccionaPor- Mérito) que analisa o mérito de todas as transacções candidatas. Esta função executa em O(n) porque o mérito de cada transacção é avaliado em tempo constante usando o sumário das relações entre as transacções. O tempo esperado de actualização do sumário é constante (no caso esperado, a execução de uma transacção influencia apenas um pequeno número de transacções). No pior caso, estas actualizações executam igualmente em O(n). A complexidade de criação do sumário (computaSumário) é O(n 2 ) porque cada par de transacções é comparado para obter as relações existentes entre elas. O ciclo de criação de soluções é igualmente executado em O(n 2 ) (no caso esperado, apenas um número reduzido de soluções são criadas). Assim, a complexidade total (esperada) do algoritmo de reconciliação (reconcilia) é O(n 2 ). Através da utilização de uma estrutura de dados especialmente adaptada à manutenção do mérito de cada transacção (baseado na utilização de filas de prioridade - priority queues) é possível reduzir a complexidade da função criaUmaSolução para O(n.logn). No entanto, a complexidade global mantém-se em O(n 2 ) devido à função computaSumário.

156 CAPÍTULO 10. SISTEMA DE RECONCILIAÇÃO SQLICECUBE<br />

criaUmaSolução ( bd, sumário, trxs) = // pseudo-código<br />

solução := []<br />

valor := 0<br />

REPEAT<br />

sumário.reinicia( trxs)<br />

WHILE sumário.algumaPossível() DO // Cria solução incr<strong>em</strong>entalmente<br />

próxTrx := seleccionaPorMérito ( sumário) // Selecciona acção a executar<br />

dynOK := bd.executaInnerTrx( próxTrx)<br />

IF dynOK = FALSE THEN // Resultado: rollback<br />

sumário.excluiTmp( próxTrx)<br />

ELSE // Resultado: commit<br />

solução := [solução|próxTrx] // Actualiza solução<br />

valor := valor + próxTrx.valor<br />

sumário.executada( próxTrx)<br />

aExcluir := incompatíveis( próxTrx, trxs) // Actualiza informação sobre transacções<br />

sumário.exclui( aExcluir)<br />

aExcluirTmp := tornaImp( próxTrx)<br />

sumário.excluiTmp( aExcluirTmp)<br />

aIncluirTmp := tornaPosAjuda( próxTrx)<br />

sumário.incluiTmp( aIncluirTmp)<br />

END IF<br />

END WHILE<br />

gtrxs = gruposIncompletos(trxs,solução) // Transacções pertencentes a grupos indivísiveis<br />

trxs = trxs \ gtrxs // parcialmente executados<br />

IF( NOT vazio(gtrxs)) THEN<br />

bd.rollbackTrx()<br />

bd.initTrx()<br />

END IF<br />

UNTIL vazio(gtrxs)<br />

RETURN { solução, valor}<br />

Figura 10.3: Algoritmo <strong>de</strong> criação <strong>de</strong> uma única solução.<br />

Se a execução da transacção seleccionada aborta, a transacção passa a ser consi<strong>de</strong>rada t<strong>em</strong>poraria-<br />

mente impossível <strong>de</strong> executar. Se uma transacção é executada com sucesso, ela é adicionada à solução<br />

parcialmente construída. A informação sobre as transacções a executar é actualizada. As transacções que<br />

são incompatíveis com a execução <strong>de</strong>ssa transacção (relações alternativas e pre<strong>de</strong>cessor/sucessor fraco)<br />

são adicionadas ao conjunto das transacções impossíveis (assim como todas as transacções que perten-<br />

çam a um grupo indivisível com uma das transacções impossíveis). As transacções que são impossibili-<br />

tadas (relação impossibilita) são adicionadas ao conjunto das transacções t<strong>em</strong>porariamente impossíveis.<br />

As transacções que são beneficiadas (relações torna possível e favorece) são r<strong>em</strong>ovidas do conjunto das<br />

transacções t<strong>em</strong>porariamente impossíveis. Em ambos os casos, o ciclo itera enquanto exist<strong>em</strong> transac-<br />

ções candidatas com mérito não nulo.<br />

Quando se conclui a criação <strong>de</strong> uma solução é necessário verificar se a solução é válida face às<br />

relações estabelecidas 3 . Para tal, é necessário verificar se existe algum grupo indivisível parcialmente<br />

executado (todas as outras relações são necessariamente satisfeitas porque nunca se selecciona uma tran-<br />

sacção cuja execução viole uma relação estática com uma transacção anteriormente executada). Em<br />

3 Uma optimização impl<strong>em</strong>entada no protótipo do sist<strong>em</strong>a consiste na verificação, s<strong>em</strong>pre que uma transacção é <strong>de</strong>clarada<br />

impossível, da impossibilida<strong>de</strong> <strong>de</strong> executar completamente qualquer grupo indivisível com transacções já executadas. Neste<br />

caso, a solução que se está a criar é <strong>de</strong>clarada imediatamente inválida.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!