Хотел написать об «отмене выполнения запросов в Firebird»… И написал.

Привет всем.

Как хорошо известно (в узких кругах) в Firebird 2.5 появилась функция отмены текущей операции с сервером — fb_cancel_operation. Штука, без сомнения, реально полезная. Но как показывает практика — ей нужно уметь пользоваться. Иначе, как показано в данном примере, можно запросто прерывать чужую работу.

Собственно говоря, моя текущая мысль не о том, что кто-то пишет в стиле «и так сойдет». А о другом. Весьма мутном.

  1. В OLEDB отмена запроса выполняется через метод ICommand::Cancel.
  2. В ADODB — через метод AdoDbCommand.Cancel
  3. В ADO.NET — DbCommand.Cancel
  4. В новом объектном API FB3 данная обязанность, как я понимаю, возложена на метод IAttachment::cancelOperation(IStatus* status, int option)

В первых трех случаях, подразумевается монопольная работа с объектом команды. Понятно — вряд ли объект команды будет параллельно использоваться несколькими потоками под разные задачи.

А в 4-ом случае, получается что монопольная работа распространяется на все подключение. Потому что cancelOperation прерывает то что есть, а не то что хотят. В результате, при прямолинейном программировании, получаем проблему обозначенную в примере.

Ну а теперь перейдем к моей «текущей мысли».

Нормальный объектный интерфейс, ориентированный на работу с несколькими клиентами (то есть — в многопоточной среде) вообще не должен иметь каких-либо методов Cancel. Клиент вызывает метод сервиса и хочет отменить именно этот вызов. Если этот метод был вызван двумя клиентами, то отмена одного не должна прерывать другого.

Такие вещи должны обеспечиваться самим сервисом (в нашем случае — это API для сервера), а не моделироваться снаружи.

Вопрос — а как? В принципе, ничего военного:

  1. В метод передается указатель на объект контекста текущей операции, в рамках которой осуществляется данный вызов.
  2. Метод может периодически спрашивать у контекста разрешения на продолжение работы. Или — регистрирует в контексте своего «представителя» с методом cancel.
  3. В случае отмены операции, контекст возводит у себя флаг «операция отменена». И, если был зарегистрирован «представитель», вызовет его метод cancel.

Именно так (внутри себя) работает IBProvider. Это его, а не .NET провайдера, заслуга в корректной работе DbCommand.Cancel-а.

В новом объектном API FB3 тоже есть вся необходимая инфраструктура в виде объекта «status», который передается в большинство интерфейсных методов и через который можно было бы прерывать их работу. Но пока мысль архитекторов моего нашего светлого будущего еще не доехала до этого.

<Дальнейший текст был вырезан военной цензурой>.

3 комментария

Симонов Денис  on 17 ноября, 2013

Вроде вот этот тикет как раз на данную тему
http://tracker.firebirdsql.org/browse/CORE-2671
По идее к бете должны пофиксить.

Kovalenko  on 17 ноября, 2013

OMG.

Ничего не надо трогать в интерфейсе старого API.

Сначала пусть исправят реализацию отмены операций:
http://tracker.firebirdsql.org/browse/CORE-3982 [slow]
http://tracker.firebirdsql.org/browse/CORE-3984 [reopen error]

Про отмену операций в Firebird (#2)  on 26 сентября, 2016

[…] Cancel-команду пока выполняется Execute. Про это было в предыдущем опусе со следующим […]

Leave a Comment