Noções básicas sobre componentes TPS
Qualquer TPS ( sistema de processamento de transações ) que use o KTM (Kernel Transaction Manager) e o CLFS ( Common Log File System ) devem conter os seguintes componentes importantes:
Um KTM ( gerenciador de transações )
A KTM acompanha o estado de cada transação e coordena as operações de recuperação após uma falha no sistema.
Um ou mais gerenciadores de recursos
Os gerenciadores de recursos, que você fornece, gerenciam os dados associados a cada transação.
Um ou mais fluxos de log CLFS
O gerenciador de transações e os gerenciadores de recursos usam fluxos de log CLFS para registrar informações que podem ser usadas para confirmar, reverter ou recuperar uma transação.
Um ou mais clientes transacionais
Normalmente, cada cliente transacional do TPS pode criar uma transação, executar operações em dados dentro do contexto da transação e, em seguida, iniciar uma operação de confirmação ou reversão para a transação.
Este tópico apresenta um TPS simples com um gerenciador de recursos, um TPS mais complexo que contém vários gerenciadores de recursos e alguns outros cenários de TPS.
A seção Usando KTM fornece informações detalhadas sobre como usar o KTM para criar componentes TPS.
TPS simples
Um TPS simples pode consistir em KTM, um gerenciador de recursos e CLFS. Os clientes transacionais podem se comunicar com o gerenciador de recursos por uma interface que o gerenciador de recursos fornece.
Por exemplo, suponha que você queira criar um sistema de gerenciamento de banco de dados. Você deseja que os clientes do sistema acessem o banco de dados abrindo um identificador para um objeto de banco de dados, executando operações de leitura e gravação no objeto e fechando o identificador do objeto.
Agora suponha que você queira que conjuntos de operações de leitura e gravação ocorram atomicamente para que outros usuários do sistema vejam apenas o resultado final. Você pode atingir essa meta projetando um TPS que permite aos clientes associar conjuntos de operações de banco de dados a uma transação.
Seu sistema deve incluir um gerenciador de recursos que gerencia os dados no banco de dados em resposta a solicitações de leitura e gravação de clientes. Esse gerenciador de recursos pode exportar uma API (interface de programação de aplicativo) que permite aos clientes associar uma transação a um conjunto de operações de leitura e gravação.
Quando o gerenciador de recursos é carregado, ele deve registrar-se com KTM chamando ZwCreateTransactionManager e ZwCreateResourceManager. Em seguida, o gerenciador de recursos pode participar de transações.
Talvez você queira que o gerenciador de recursos dê suporte a um conjunto de funções que permitem que os clientes criem objetos de dados, leiam e escrevam dados associados aos objetos de dados e fechem os objetos de dados. O pseudocódigo a seguir mostra uma sequência de código de exemplo de um cliente.
CreateDataObject (IN TransactionID, OUT DataHandle);
ReadData (IN DataHandle, OUT Data);
WriteData (IN DataHandle, IN Data);
WriteData (IN DataHandle, IN Data);
WriteData (IN DataHandle, IN Data);
CloseDataObject (IN DataHandle);
Antes que um cliente possa chamar a rotina CreateDataObject do gerenciador de recursos, o cliente deve criar um objeto de transação chamando a rotina ZwCreateTransaction da KTM e obter o identificador do objeto de transação chamando ZwQueryInformationTransaction.
Quando o cliente chama a rotina CreateDataObject do gerenciador de recursos, o cliente passa o identificador do objeto de transação para o gerenciador de recursos. O gerenciador de recursos pode chamar ZwOpenTransaction para obter um identificador para o objeto de transação e, em seguida, pode chamar ZwCreateEnlistment para registrar sua participação na transação.
Neste ponto, o cliente pode começar a executar operações no objeto de dados. Como o cliente forneceu um identificador de transação quando criou o objeto de dados, o gerenciador de recursos pode atribuir todas as operações de leitura e gravação à transação.
O gerenciador de recursos deve registrar todos os resultados das operações de dados especificadas pelo cliente sem tornar os resultados permanentes. Normalmente, o gerenciador de recursos usa CLFS para registrar os resultados da operação em um fluxo de log de transações.
Quando o cliente terminar de chamar o gerenciador de recursos para executar operações transacionais, ele chamará a rotina ZwCommitTransaction da KTM. Neste ponto, a KTM notifica o gerenciador de recursos de que ele deve tornar as operações permanentes. Em seguida, o gerenciador de recursos move os resultados da operação do fluxo de log para o meio de armazenamento permanente dos dados. Por fim, o gerenciador de recursos chama ZwCommitComplete para informar à KTM que a operação de confirmação está concluída.
O que acontece se o gerenciador de recursos relatar um erro para uma das chamadas do cliente para ReadData ou WriteData? O cliente pode chamar ZwRollbackTransaction para reverter a transação. Como resultado dessa chamada, a KTM notifica o gerenciador de recursos de que ele deve restaurar os dados para seu estado original. Em seguida, o cliente pode criar uma nova transação para as mesmas operações ou pode optar por não continuar.
O pseudocódigo a seguir mostra um exemplo de uma sequência mais detalhada das operações transacionais de um cliente.
ZwCreateTransaction (&TransactionHandle, ...);
ZwQueryInformationTransaction (TransactionHandle, ...);
CreateDataObject (TransactionID, &DataHandle);
Status = ReadData (DataHandle, &Data1);
if (Status == Error) goto ErrorRollback;
Status = WriteData (DataHandle, Data2);
if (Status == Error) goto ErrorRollback;
Status = WriteData (DataHandle, Data3);
if (Status == Error) goto ErrorRollback;
Status = WriteData (DataHandle, Data4);
if (Status == Error) goto ErrorRollback;
ZwCommitTransaction (TransactionHandle, ...);
goto Leave;
ErrorRollback:
ZwRollbackTransaction (TransactionHandle, ...);
Leave:
ZwClose (TransactionHandle);
return;
O que acontece se o sistema falhar depois que a transação for criada, mas antes de ser confirmada ou revertida? Sempre que o gerenciador de recursos é carregado, ele deve chamar ZwRecoverTransactionManager e ZwRecoverResourceManager. Chamar ZwRecoverTransactionManager faz com que a KTM abra seu fluxo de log e leia o histórico de transações. Chamar ZwRecoverResourceManager faz com que o KTM notifique o gerenciador de recursos de todas as transações inscridas que estavam em andamento antes da falha e quais transações o gerenciador de recursos deve, portanto, recuperar.
Se um cliente transacional chamado ZwCommitTransaction para uma transação antes da falha e começou a lidar com operações de confirmação para a transação, o gerenciador de recursos deverá ser capaz de restaurar o estado da transação para o ponto imediatamente antes da falha. Se o cliente não estava pronto para confirmar a transação antes da falha, o gerenciador de recursos poderá descartar os dados e reverter a transação.
Para obter mais informações sobre como gravar clientes transacionais, consulte Criando um cliente transacional.
Para obter mais informações sobre como escrever gerenciadores de recursos, consulte Criando um Resource Manager.
Vários Resource Managers em um TPS
Agora suponha que o TPS permita que os clientes modifiquem informações em dois bancos de dados separados em uma única transação, para que a transação seja bem-sucedida somente se as modificações de ambos os bancos de dados forem bem-sucedidas.
Nesse caso, o TPS pode ter dois gerenciadores de recursos, um para cada banco de dados. Cada gerenciador de recursos pode exportar uma API que os clientes podem usar para acessar o banco de dados do gerenciador de recursos.
O pseudocódigo a seguir mostra como um cliente pode criar uma única transação que contenha operações em dois bancos de dados compatíveis com dois gerenciadores de recursos.
Neste exemplo, o cliente lê dados do primeiro banco de dados e os grava no segundo banco de dados. Em seguida, o cliente lê dados do segundo banco de dados e os grava no primeiro banco de dados. (O primeiro gerenciador de recursos exporta funções que começam com rm1 e o segundo gerenciador de recursos exporta funções que começam com Rm2.)
ZwCreateTransaction (&TransactionHandle, ...);
ZwQueryInformationTransaction (TransactionHandle, ...);
Rm1CreateDataObject (TransactionID, &Rm1DataHandle);
Rm2CreateDataObject (TransactionID, &Rm2DataHandle);
Status = Rm1ReadData (Rm1DataHandle, &Rm1Data);
if (Status == Error) goto ErrorRollback;
Status = Rm2WriteData (Rm2DataHandle, Rm1Data);
if (Status == Error) goto ErrorRollback;
Status = Rm2ReadData (Rm2DataHandle, &Rm2Data);
if (Status == Error) goto ErrorRollback;
Status = Rm1WriteData (Rm1DataHandle, Rm2Data);
if (Status == Error) goto ErrorRollback;
ZwCommitTransaction (TransactionHandle, ...);
goto Leave;
ErrorRollback:
ZwRollbackTransaction (TransactionHandle, ...);
Leave:
ZwClose (TransactionHandle);
return;
Como o cliente passa o mesmo identificador de transação para ambos os gerenciadores de recursos, ambos os gerenciadores de recursos podem chamar ZwOpenTransaction e ZwCreateEnlistment para se inscreverem na transação. Quando o cliente eventualmente chama ZwCommitTransaction, o KTM notifica cada gerenciador de recursos de que o gerente deve tornar as operações permanentes e cada gerenciador de recursos chama ZwCommitComplete quando terminar.
Outros cenários de TPS
O KTM dá suporte a outros cenários de TPS. Por exemplo, os seguintes cenários descrevem componentes que um TPS pode conter:
Um gerenciador de recursos que gerencia vários bancos de dados.
A API do gerenciador de recursos poderia permitir que os clientes abrissem e acessassem mais de um banco de dados por vez e o cliente pudesse combinar acessos a vários bancos de dados em uma única transação.
Um gerenciador de recursos com uma API que os clientes chamam e outros gerenciadores de recursos com APIs que o primeiro gerenciador de recursos chama.
O cliente se comunica apenas com o primeiro gerenciador de recursos. Quando esse gerenciador de recursos processa solicitações de um cliente, ele pode acessar os gerenciadores de recursos adicionais, conforme necessário, para processar as solicitações do cliente. Por exemplo, um gerenciador de recursos gerencia um banco de dados acessível pelo cliente que requer operações de backup ou verificação de dados de um segundo gerenciador de recursos que não está disponível para clientes.
Um cliente e gerenciador de recursos existentes que não usam KTM, integrado a um conjunto adicional de gerenciadores de recursos que usam KTM.
Nesse caso, normalmente você precisa modificar o gerenciador de recursos existente para que ele se torne um gerenciador de transações superior que se comunique com KTM.