Основные сведения о компонентах TPS
Любая система обработки транзакций (TPS), использующая диспетчер транзакций ядра (KTM) и общую файловую систему журналов (CLFS), должна содержать следующие важные компоненты:
Диспетчер транзакций (KTM)
KTM отслеживает состояние каждой транзакции и координирует операции восстановления после сбоя системы.
Один или несколько диспетчеров ресурсов
Предоставляемые вами диспетчеры ресурсов управляют данными, связанными с каждой транзакцией.
Один или несколько потоков журналов CLFS
Диспетчер транзакций и диспетчер ресурсов используют потоки журналов CLFS для записи сведений, которые можно использовать для фиксации, отката или восстановления транзакции.
Один или несколько транзакционных клиентов
Как правило, каждый транзакционный клиент TPS может создать транзакцию, выполнить операции с данными в контексте транзакции, а затем инициировать операцию фиксации или отката для транзакции.
В этом разделе вы познакомите с простым TPS с одним диспетчером ресурсов, более сложным TPS, содержащим несколько диспетчеров ресурсов, и некоторыми другими сценариями TPS.
В разделе Использование KTM содержатся подробные сведения о том, как использовать KTM для создания компонентов TPS.
Простая TPS
Простой TPS может состоять из KTM, одного диспетчера ресурсов и CLFS. Транзакционные клиенты могут взаимодействовать с диспетчером ресурсов с помощью интерфейса, который предоставляет диспетчер ресурсов.
Например, предположим, что вы хотите создать систему управления базами данных. Клиенты системы должны обращаться к базе данных, открыв дескриптор объекта базы данных, выполняя операции чтения и записи объекта, а затем закрывая дескриптор объекта.
Теперь предположим, что вы хотите, чтобы наборы операций чтения и записи происходили атомарно, чтобы другие пользователи системы видели только конечный результат. Эту цель можно достичь, разработав TPS, которая позволяет клиентам привязывать наборы операций базы данных к транзакции.
Ваша система должна включать диспетчер ресурсов, который управляет данными в базе данных в ответ на запросы на чтение и запись от клиентов. Этот диспетчер ресурсов может экспортировать программный интерфейс приложения (API), который позволяет клиентам связывать транзакцию с набором операций чтения и записи.
При загрузке диспетчера ресурсов необходимо зарегистрировать себя в KTM, вызвав ZwCreateTransactionManager и ZwCreateResourceManager. Затем диспетчер ресурсов может участвовать в транзакциях.
Может потребоваться, чтобы диспетчер ресурсов поддерживал набор функций, позволяющих клиентам создавать объекты данных, считывать и записывать данные, связанные с объектами данных, а также закрывать объекты данных. В следующем псевдокоде показан пример последовательности кода клиента.
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);
Прежде чем клиент сможет вызвать подпрограмму CreateDataObject диспетчера ресурсов, клиент должен создать объект транзакции, вызвав подпрограмму KTM ZwCreateTransaction , и получить идентификатор объекта транзакции, вызвав ZwQueryInformationTransaction.
Когда клиент вызывает подпрограмму CreateDataObject диспетчера ресурсов, клиент передает идентификатор объекта транзакции диспетчеру ресурсов. Диспетчер ресурсов может вызвать ZwOpenTransaction , чтобы получить дескриптор объекта транзакции, а затем вызвать ZwCreateEnlistment , чтобы зарегистрировать свое участие в транзакции.
На этом этапе клиент может приступить к выполнению операций с объектом данных. Так как клиент предоставил идентификатор транзакции при создании объекта данных, диспетчер ресурсов может назначить транзакцию все операции чтения и записи.
Диспетчер ресурсов должен записывать все результаты операций с данными, которые указывает клиент, не делая результаты постоянными. Как правило, диспетчер ресурсов использует CLFS для записи результатов операции в поток журнала транзакций.
Когда клиент завершит вызов диспетчера ресурсов для выполнения транзакционных операций, он вызывает подпрограмму KTM ZwCommitTransaction . На этом этапе KTM уведомляет диспетчер ресурсов о том, что он должен сделать операции постоянными. Затем диспетчер ресурсов перемещает результаты операции из потока журнала в постоянное хранилище данных. Наконец, диспетчер ресурсов вызывает ZwCommitComplete , чтобы сообщить KTM о завершении операции фиксации.
Что произойдет, если диспетчер ресурсов сообщит об ошибке для одного из вызовов клиента ReadData или WriteData? Клиент может вызвать ZwRollbackTransaction для отката транзакции. В результате этого вызова KTM уведомляет диспетчер ресурсов о том, что ему следует восстановить данные в исходное состояние. Затем клиент может либо создать новую транзакцию для тех же операций, либо отказаться от продолжения.
В следующем псевдокоде показан пример более подробной последовательности транзакционных операций клиента.
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;
Что произойдет, если система аварийно завершает работу после создания транзакции, но до ее фиксации или отката? При каждой загрузке диспетчер ресурсов должен вызывать ZwRecoverTransactionManager и ZwRecoverResourceManager. Вызов ZwRecoverTransactionManager приводит к открытию KTM потока журнала и чтению журнала транзакций. Вызов ZwRecoverResourceManager приводит к тому, что KTM уведомляет диспетчер ресурсов о всех прикрепленных транзакциях, которые выполняются до сбоя и какие транзакции необходимо восстановить.
Если транзакционный клиент вызывал ZwCommitTransaction для транзакции перед сбоем и начал обрабатывать операции фиксации для транзакции, диспетчер ресурсов должен иметь возможность восстановить состояние транзакции до точки непосредственно перед сбоем. Если клиент не был готов к фиксации транзакции до сбоя, диспетчер ресурсов может удалить данные и откатить транзакцию.
Дополнительные сведения о записи транзакционных клиентов см. в разделе Создание транзакционного клиента.
Дополнительные сведения о создании диспетчеров ресурсов см. в статье Создание Resource Manager.
Несколько диспетчеров ресурсов в TPS
Теперь предположим, что TPS позволяет клиентам изменять сведения в двух отдельных базах данных в рамках одной транзакции, чтобы транзакция была успешной только в том случае, если изменения обеих баз данных были успешными.
В этом случае ваш TPS может иметь два диспетчера ресурсов, по одному для каждой базы данных. Каждый диспетчер ресурсов может экспортировать API, который клиенты могут использовать для доступа к базе данных диспетчера ресурсов.
В следующем псевдокоде показано, как клиент может создать одну транзакцию, содержащую операции в двух базах данных, которые поддерживаются двумя диспетчерами ресурсов.
В этом примере клиент считывает данные из первой базы данных и записывает их во вторую базу данных. Затем клиент считывает данные из второй базы данных и записывает их в первую базу данных. (Первый диспетчер ресурсов экспортирует функции, начинающиеся с Rm1, а второй — функции, начинающиеся с 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;
Так как клиент передает один и тот же идентификатор транзакции обоим диспетчерам ресурсов, оба диспетчера ресурсов могут вызывать ZwOpenTransaction и ZwCreateEnlistment для зачисления в транзакцию. Когда клиент в конечном итоге вызывает ZwCommitTransaction, KTM уведомляет каждого диспетчера ресурсов о том, что он должен сделать операции постоянными, и каждый диспетчер ресурсов вызывает ZwCommitComplete по завершении.
Другие сценарии TPS
KTM поддерживает другие сценарии TPS. Например, в следующих сценариях описываются компоненты, которые может содержать TPS:
Один диспетчер ресурсов, который управляет несколькими базами данных.
API диспетчера ресурсов позволяет клиентам открывать и получать доступ к нескольким базам данных одновременно, а клиент может объединять доступы к нескольким базам данных в одной транзакции.
Один диспетчер ресурсов с API, который вызывает клиенты, и дополнительные диспетчеры ресурсов с API, которые вызывает первый диспетчер ресурсов.
Клиент взаимодействует только с первым диспетчером ресурсов. Когда диспетчер ресурсов обрабатывает запросы от клиента, он при необходимости может получить доступ к дополнительным диспетчерам ресурсов для обработки запросов клиента. Например, диспетчер ресурсов управляет базой данных, доступной клиенту, которая требует операций резервного копирования или проверки данных из второго диспетчера ресурсов, недоступного для клиентов.
Существующий клиент и диспетчер ресурсов, которые не используют KTM, интегрированы с дополнительным набором диспетчеров ресурсов, использующих KTM.
В этом случае обычно необходимо изменить существующий диспетчер ресурсов, чтобы он стал превосходным диспетчером транзакций , взаимодействующим с KTM.