Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ
Шрифт:
Вы можете спросить, почему мы должны интересоваться системой блокировки, которая ничего не блокирует? Параллельность и согласованность, видимые клиентам, основываются на транзакциях и управляются через версии записей. Однако ответ в том, что Firebird использует блокировки внутренне. Он поддерживает согласованность структуры на диске через блокировки и осторожную запись. В то же время он также использует сервисы блокировок операционной системы для управления доступом к файлам базы данных для предотвращения открытия Суперсервером дважды одного и того же файла под разными именами.
Блокировка, основанная на транзакциях, позволяет осуществлять блокировки в любой точке выполнения транзакции.
Firebird остерегается двухфазной блокировки для своего первичного управления параллельностью, поскольку она не может обеспечить адекватных уровней параллельности и соответствия, Firebird использует блокировки в процессе изменений для предотвращения записи двумя транзакциями на одну и ту же страницу в одно и то же время. Внутренняя блокировка управляется самой системой. Объекты в системе - называемые "владельцами блокировки" или просто "владельцами" - состязаются в блокировке множества ресурсов. Не удивительно, что эти ресурсы включают в себя и страницы, содержащие записи, отмеченные для обновления.
Когда транзакция получает блокировку страницы, она сохраняет эту блокировку, пока Менеджер блокировок не попросит ее освободить страницу; следовательно, транзакция может выполнить множество изменений на одной странице без ее освобождения и повторного чтения.
Менеджер блокировок Firebird
В Суперсервере о Менеджере блокировок можно думать как об отдельном "управляющем центре", с которым договариваются транзакции о приобретении прав на выполнение запросов. Менеджер блокировок включает в себя фрагмент памяти и некоторые подпрограммы для обработки запросов. Его память разделена на различные блоки: блоки блокировок, которые ссылаются на ресурсы; другие блоки, которые представляют транзакции и другие объекты, запрашивающие блокировки, и блоки истории. Его подпрограммы ответственны за получение и управление запросами владельцев на блокировки ресурсов, выделение блоков и их освобождение. Суперсервер также управляет "защелками" для координации изменений в параллельных транзакциях.
Классический сервер проще: владельцы запрашивают получение контроля над таблицей блокировок, так что каждый код процесса управления блокировкой может запрашивать, предоставлять и освобождать блокировки для их владельцев.
Состояния блока
Каждая операционная система предоставляет некий вид механизма использования/освобождения для синхронизации событий ресурсов. Поскольку для Firebird нужен управляющий механизм с множеством состояний, он реализует свою собственную систему управления блокировками с семью состояниями. На рис. 40.1 показано решение уровней блокировок.
* 0 - свободно (no lock).
* 1 - пустая блокировка (null lock), что соответствует интересу объекта, не накладывающего ограничений в использовании другими. Запрос пустой блокировки позволяет транзакции читать заблокированные данные.
* 2 - разделяемое чтение (shared read), что позволяет записывать. Разделяемое чтение является обычным режимом для блокировки таблицы, когда транзакция изменяет некоторые части таблицы.
* 3 - защищенное чтение (protected read), что позволяет другим читать, но не писать. Защищенное чтение является обычным режимом для блокировки страницы базы данных, которая находится в кэше и не была изменена.
Рис. 40.1.
Состояния внутренних блокировок Firebird* 4 - совместно используемая запись (shared write), другой обычный режим блокировки таблицы. Совместно используемая запись совместима с разделяемым чтением и другими совместно используемыми записями, но не с любым защищенным режимом.
* 5 - защищенная запись (protected write), которая допускает разделяемое чтение и пустую блокировку и ничего больше. Защищенная запись используется при режиме CONSISTENCY и для такой блокировки базы данных, что обычные пользователи не могут получить к ней доступ.
* 6 - исключительный доступ (exclusive), используется для внутренних структур, когда параллельный доступ может повлиять на изменения или привести к тому, что вторая транзакция будет читать незавершенные изменения данных.
Таблица блокировок
Менеджер блокировок управляет таблицей блокировок для координации совместного использования ресурсов в клиентских потоках. Информация, предоставляемая здесь, может быть полезной при попытках исправить ситуации взаимных блокировок, например;
* все в настоящий момент заблокировано в системе в своем состоянии;
* глобальная статистика заголовков, такая как размер таблицы блокировок, множество свободных блокировок, множество взаимных блокировок и т.д.;
* флаги процессов, указывающие, была ли передана блокировка или она осуществляет ожидание.
Блокировки сохраняются в последовательностях, каждая последовательность идентифицируется номером в соответствии с типом блокируемого ресурса. Номера последовательностей объясняются в табл. 40.5.
Запущенная транзакция использует таблицу блокировок в качестве доски объявлений. Чтобы исключить сборку мусора версий записей, которые нужны другой транзакции, каждая транзакция должна знать самое старое действие, которое видит другая транзакция. Вот как это сделано:
1. При старте транзакция сохраняет в области данных собственного блока идентификатор старейшей транзакции, которая еще выполняется (активна).
2. Затем она устанавливает пустую блокировку на все параллельные транзакции. Когда будет получен каждый блок, ей возвращается содержимое области данных.
Новая транзакция проверяет блок каждой существующей транзакции для отыскания идентификатора старейшей транзакции, о которой знает каждая активная транзакция.
Списки владельцев, ресурсов и запросов представлены в виде цепочки с возможностью проходить по ним вперед и назад. В начале каждого блока находится указатель на следующий блок. Списки указателей используются Менеджером блокировок, когда ему нужно разместить новый блок и постараться найти свободные блоки для повторного использования. Он выделит новый блок, только если не существует свободных блоков нужного типа и размера.
Свободные элементы содержат прямые и обратные указатели на первый и последний свободный блок соответственно.
Взаимная блокировка (deadlock) возникает, когда владелец А хочет блокировать ресурс 1, который заблокирован владельцем В, а владелец В хочет заблокировать ресурс 2, который заблокирован процессом А. Она также может появиться для одного ресурса, если два владельца начинают с блокировки чтения и запрашивают блокировки на запись.