Глава 8. Надёжность

8.1 Модель надёжности

Реализация DTP MUST обеспечивать следующие гарантии надёжности:

  1. Возобновление: после разрыва нижележащего соединения передача возобновляется; данные, уже успешно полученные, MUST NOT повторно передаваться.
  2. Подтверждение: получатель MUST подтверждать отправителю Fragment, которые были успешно получены.
  3. Повторная передача: отправитель MUST повторно передавать неподтверждённые Fragment, если подтверждение не получено в пределах тайм-аута.
  4. Сохранение Session: при разрыве нижележащего соединения состояние Session MUST быть сохранено.

8.2 Механизм возобновления

8.2.1 Протокол возобновления

Возобновление MUST реализовываться на основе порядковых номеров и следовать данному рабочему процессу:

Sender                                Receiver
   |                                     |
   |-- Fragment (seq=1) ---------------->|  ✓ received
   |-- Fragment (seq=2) ---------------->|  ✓ received
   |-- Fragment (seq=3) ---------------->|  ✓ received
   |-- Fragment (seq=4) -------- ✗ -----|  connection lost
   |                                     |
   |        [connection restored]        |
   |                                     |
   |<-- ResumeReport (highest=3) --------|
   |                                     |
   |-- Fragment (seq=4) ---------------->|  resume from breakpoint
   |-- Fragment (seq=5) ---------------->|

8.2.2 ResumeReport

После восстановления соединения получатель MUST отправить ResumeReport, определённый следующим образом:

interface ResumeReport {
  collectionHighest: SequenceNumber;
  injectionHighest: SequenceNumber;
}
ПолеНормативное требование
collectionHighestMUST быть наибольшим порядковым номером, успешно полученным получателем в направлении сбора данных
injectionHighestMUST быть наибольшим порядковым номером, успешно полученным получателем в направлении инжекции данных

Если в каком-либо направлении ещё не получено ни одного Fragment, соответствующее поле MUST быть равно -1 или другому определяемому реализацией дозорному значению «не получено».

8.2.3 Согласованность возобновления

После получения ResumeReport отправитель MUST строго следовать следующим правилам:

  1. Продолжать со следующего порядкового номера: возобновить отправку, начиная с highest + 1.
  2. Не отправлять повторно: MUST NOT повторно отправлять любой Fragment с порядковым номером <= highest.
  3. Не пропускать: MUST NOT пропускать неподтверждённые Fragment (т.е. те, что не подтверждены в кэше).

8.3 Механизм подтверждения

8.3.1 Способы подтверждения

Реализация MUST обеспечивать подтверждение получения Fragment. Подтверждение MAY реализовываться через один из следующих способов:

  1. Явный ACK control-фрейм: получатель отправляет ControlFrame с controlType = "ack", в котором details содержит наибольший подтверждённый порядковый номер.
  2. Кумулятивный ACK: переносить наибольший полученный порядковый номер обратного направления в поле расширения каждого data-фрейма (RECOMMENDED).
  3. Пакетный ACK: отправлять один ACK на каждые N полученных Fragment (N определяется реализацией; RECOMMENDED значение 16).

Конкретный способ подтверждения MAY выбираться реализацией, но получатель и отправитель MUST прийти к согласию относительно выбранного способа.

8.3.2 Время подтверждения

Получатель MUST удовлетворять следующим требованиям:

  1. Подтверждать только после того, как Fragment прошёл расшифровку, валидацию Agreement и валидацию DAG.
  2. MUST NOT подтверждать, пока состояние DAG равно pending (подтверждение должно быть отложено до разрешения зависимостей).
  3. Наибольший порядковый номер в ACK MUST быть максимумом непрерывного префикса множества подтверждённых порядковых номеров.

8.4 Механизм повторной передачи

8.4.1 Стратегия повторной передачи

Отправитель MUST повторно передавать при следующих условиях:

  1. ACK для заданного порядкового номера не получен в пределах настроенного протоколом тайм-аута повторной передачи.
  2. При получении ResumeReport повторно передать неподтверждённые Fragment.

8.4.2 Конфигурация повторной передачи

Реализация SHOULD предоставлять следующие настраиваемые параметры:

ПараметрПо умолчанию (RECOMMENDED)Описание
Начальный тайм-аут повторной передачи5 секундВремя ожидания первой повторной передачи
Коэффициент отката повторной передачи2Тайм-аут удваивается после каждой повторной передачи (экспоненциальный откат)
Максимальное число повторных передач5По превышении этого числа уведомить верхний уровень о неудаче
Максимальный тайм-аут повторной передачи60 секундВерхняя граница тайм-аута повторной передачи

Реализация MUST реализовывать алгоритм экспоненциального отката.

8.4.3 Обработка неудач повторной передачи

При превышении верхнего предела числа повторных передач:

  1. Отправитель MUST уведомить приложение верхнего уровня об ошибке RETRANSMISSION_TIMEOUT (6002).
  2. Отправитель SHOULD инициировать приостановку или прекращение Session (определяется реализацией).
  3. Реализация MUST NOT повторно передавать бесконечно.

8.5 Управление кэшем

8.5.1 Кэш неподтверждённых Fragment

Отправитель MUST поддерживать кэш неподтверждённых Fragment, удовлетворяющий следующим требованиям:

  1. Каждый Fragment, который был отправлен, но ещё не подтверждён, MUST сохраняться в кэше.
  2. После получения подтверждения подтверждённый Fragment MUST быть удалён из кэша.
  3. Кэш MUST иметь верхнюю границу ёмкости (определяется реализацией; RECOMMENDED не менее 1024 Fragment или 16 МБ).

8.5.2 Обработка переполнения кэша

При достижении кэшем верхней границы ёмкости отправитель MUST:

  1. Приостановить отправку новых Fragment.
  2. Уведомить приложение верхнего уровня через ошибку BUFFER_FULL (6001).
  3. Возобновить отправку после освобождения места в кэше за счёт подтверждений.
  4. MUST NOT молча отбрасывать Fragment.

8.6 Управление сессиями

8.6.1 Установление Session

После того как CAP завершил аутентификацию и обмен ключами, DTP_Engine MUST установить DTP-сессию:

  1. MUST сгенерировать уникальный Session_ID (UUID v4) в соответствии с RFC 4122.
  2. MUST инициализировать структуру данных Session (см. раздел 8.6.3).
  3. MUST перевести состояние из WaitingForCAP в SessionEstablished.

8.6.2 Поддержка состояния Session

В течение Session DTP_Engine MUST поддерживать состояние двунаправленной передачи:

interface DirectionalTransferState {
  currentSequenceNumber: SequenceNumber;
  highestAcknowledgedSequenceNumber: SequenceNumber;
  unacknowledgedFragmentCache: Map<SequenceNumber, Fragment>;
}

Реализация MUST поддерживать независимый DirectionalTransferState для каждого направления передачи:

НаправлениеИмя поля
Сбор данных (Терминал → Fay)collectionState
Инжекция данных (Fay → Терминал)injectionState

8.6.3 Структура данных Session

Полная структура Session MUST содержать:

interface Session {
  sessionId: SessionID;
  masterIdentity: string;
  slaveIdentity: string;
  state: SessionState;
  activeAgreements: Map<AgreementID, Agreement>;
  collectionState: DirectionalTransferState;
  injectionState: DirectionalTransferState;
  createdAt: number;
  lastActivityAt: number;
  timeoutThreshold: number;
}

8.6.4 Сохранение Session

При разрыве нижележащего транспортного соединения DTP_Engine MUST:

  1. Немедленно перевести SessionState из Transmitting в Suspended.
  2. Сохранить в энергонезависимое хранилище:
    • Полный объект Session (включая все активные Agreement)
    • Двунаправленные DirectionalTransferState
    • Кэш неподтверждённых Fragment
  3. Сохранение MUST быть атомарным (либо всё успешно, либо всё неудачно).

8.6.5 Восстановление Session

После повторного установления нижележащего соединения DTP_Engine MUST следовать следующему процессу восстановления:

  1. Дождаться повторной верификации CAP.
  2. После успешной верификации CAP перейти в состояние Resuming.
  3. Восстановить состояние Session из персистентного хранилища.
  4. Получатель отправляет ResumeReport (см. раздел 8.2.2).
  5. На основе ResumeReport отправитель возобновляет передачу с точки прерывания.
  6. После завершения резюм-рукопожатия перейти в Transmitting.

При неудачном восстановлении DTP_Engine MUST:

  1. Перейти в состояние Idle.
  2. Освободить все связанные ресурсы.
  3. Уведомить верхний уровень через ошибку SESSION_RESTORE_FAILED (5003).

8.6.6 Тайм-аут Session

Реализация MUST реализовывать механизм тайм-аута Session:

  1. MUST поддерживать поле lastActivityAt, фиксирующее время последней активности.
  2. Когда now - lastActivityAt > timeoutThreshold, Session MUST быть помечена как истёкшая по тайм-ауту.
  3. Истёкшая по тайм-ауту Session MUST быть закрыта, и связанные ресурсы MUST быть освобождены.
  4. Значение timeoutThreshold по умолчанию RECOMMENDED равным 30 минутам (1 800 000 мс).

8.7 Двунаправленная независимость

Реализация MUST строго гарантировать независимость двух направлений передачи:

  1. Изменения состояния в направлении сбора данных MUST NOT влиять на направление инжекции данных.
  2. Аномалия соединения в одном направлении MUST NOT автоматически вызывать изменение состояния в другом направлении (если только нижележащее соединение не разорвано полностью).
  3. Порядковые номера одного направления MUST NOT попадать в пространство порядковых номеров другого направления.
  4. Кэш одного направления MUST NOT потреблять квоту кэша другого направления.