Основные сведения о компонентах 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.