Хотел написать об «отмене выполнения запросов в Firebird»… И написал.
Привет всем.
Как хорошо известно (в узких кругах) в Firebird 2.5 появилась функция отмены текущей операции с сервером — fb_cancel_operation. Штука, без сомнения, реально полезная. Но как показывает практика — ей нужно уметь пользоваться. Иначе, как показано в данном примере, можно запросто прерывать чужую работу.
Собственно говоря, моя текущая мысль не о том, что кто-то пишет в стиле «и так сойдет». А о другом. Весьма мутном.
- В OLEDB отмена запроса выполняется через метод ICommand::Cancel.
- В ADODB — через метод AdoDbCommand.Cancel
- В ADO.NET — DbCommand.Cancel
- В новом объектном API FB3 данная обязанность, как я понимаю, возложена на метод IAttachment::cancelOperation(IStatus* status, int option)
В первых трех случаях, подразумевается монопольная работа с объектом команды. Понятно — вряд ли объект команды будет параллельно использоваться несколькими потоками под разные задачи.
А в 4-ом случае, получается что монопольная работа распространяется на все подключение. Потому что cancelOperation прерывает то что есть, а не то что хотят. В результате, при прямолинейном программировании, получаем проблему обозначенную в примере.
Ну а теперь перейдем к моей «текущей мысли».
Нормальный объектный интерфейс, ориентированный на работу с несколькими клиентами (то есть — в многопоточной среде) вообще не должен иметь каких-либо методов Cancel. Клиент вызывает метод сервиса и хочет отменить именно этот вызов. Если этот метод был вызван двумя клиентами, то отмена одного не должна прерывать другого.
Такие вещи должны обеспечиваться самим сервисом (в нашем случае — это API для сервера), а не моделироваться снаружи.
Вопрос — а как? В принципе, ничего военного:
- В метод передается указатель на объект контекста текущей операции, в рамках которой осуществляется данный вызов.
- Метод может периодически спрашивать у контекста разрешения на продолжение работы. Или — регистрирует в контексте своего «представителя» с методом cancel.
- В случае отмены операции, контекст возводит у себя флаг «операция отменена». И, если был зарегистрирован «представитель», вызовет его метод cancel.
Именно так (внутри себя) работает IBProvider. Это его, а не .NET провайдера, заслуга в корректной работе DbCommand.Cancel-а.
В новом объектном API FB3 тоже есть вся необходимая инфраструктура в виде объекта «status», который передается в большинство интерфейсных методов и через который можно было бы прерывать их работу. Но пока мысль архитекторов моего нашего светлого будущего еще не доехала до этого.
<Дальнейший текст был вырезан военной цензурой>.
Симонов Денис on 17 ноября, 2013
Вроде вот этот тикет как раз на данную тему
http://tracker.firebirdsql.org/browse/CORE-2671
По идее к бете должны пофиксить.