Лекция (2) (1121831), страница 10
Текст из файла (страница 10)
Алгоритм MVTO работает следующим образом.
-
Любая операция Ri(o) преобразуется в операцию Ri(ok), где ok – это версия объекта o, помеченная наибольшей временной меткой t(Tk), такой что t(Tk)
t(Ti). Другими словами, транзакции Ti для чтения дается версия объекта o, созданная транзакцией Tk, которая не моложе Ti, но старше любой другой транзакции Tn, создававшей свою версию объекта o.
-
При обработке операции Wi(o) выполняются следующие действия:
-
если к этому времени некоторой незафиксированной транзакцией Tn уже выполнена некоторая операция Rn(ok), такая что t(Tk)
t(Ti) < t(Tn), то операция Wi(o) не выполняется, а транзакция Ti откатывается;
-
в противном случае Wi(o) преобразуется в Wi(oi), т.е. образуется еще одна версия объекта o.
-
При откате любой транзакции уничтожаются все созданные ею версии объектов базы данных и откатываются все транзакции, прочитавшие хотя бы одну из этих версий. Тем самым, откаты транзакций могут быть «каскадными».
Выполнение операции фиксации транзакции Ti (COMMIT) откладывается до того момента, когда завершатся все транзакции, записавшие версии данных, прочитанные Ti. Легко видеть, что без соблюдения этого требования не соблюдалось бы свойство долговечности (durability) транзакций, поскольку при откате некоторых транзакций потребовалось бы откатывать и ранее зафиксированные транзакции.
Преимущества алгоритма MVTO лучше всего иллюстрируются поведением транзакций T1 и T2 (см. рис. 13.8). При использовании блокировок между ними возник бы синхронизационный тупик, а при использовании обычного метода временных меток одна из транзакций подверглась бы откату. Однако при применении версий такие неприятности не возникают из-за того, что первая транзакция читает «старые» версии объектов o и ω.
Рис. 13.8. Пример работы алгоритма MVTO
Транзакция T3 ожидает фиксации транзакции T2 перед своим собственным завершением (на рис. 13.8 это показано пунктирной линией). Это происходит потому, что транзакция T3 прочитала версию o2 объекта o, образованную еще не зафиксированной транзакцией.
Транзакция T4 пытается создать версию ω4 объекта ω после того, как еще не зафиксированная транзакция T5 (начавшаяся позже) уже прочитала более раннюю версию ω4. Поэтому транзакция T5 не сможет «увидеть» изменения объекта ω, произведенные транзакцией T4. Следовательно, сериализация транзакций в порядке получения ими временных меток становится невозможной, и приходится произвести откат транзакции T4.
Итак, основными преимуществами алгоритма MVTO является отсутствие задержек и откатов при выполнении операций чтения, а основным недостатком – возможность возникновение каскадных откатов транзакций при выполнении операций записи. Кроме того, в базе данных может накапливаться произвольное число версий одного и того же объекта, и определение того, какие версии больше не требуются, является серьезной технической проблемой.
Версионный вариант двухфазного протокола синхронизационных блокировок
При описании двухверсионного варианта протокола 2PL (Two-Version Two-Phase Locking Protocol, 2V2PL) будем называть текущими версиями объектов базы данных версии, созданные зафиксированными транзакциями с наиболее поздним временем фиксации; незафиксированными версиями – версии, созданные еще незавершившимися транзакциями. При следовании протоколу 2V2PL в каждый момент времени существует не более одной незафиксированной версии каждого объекта базы данных.
Операции любой транзакции Ti над объектом базы данных o обрабатываются следующим образом:
-
операция Ri(o) немедленно выполняется над текущей версией объекта o;
-
операция Wi(o), приводящая к созданию новой версии объекта o, выполняется только после завершения (фиксации или отката) транзакции, создавшей незафиксированную версию объекта o;
-
выполнение операции COMMIT откладывается до тех пор, пока не завершатся все транзакции Tk, прочитавшие текущие версии объектов базы данных, которые должны замениться незафиксированными версиями этих объектов, созданными транзакцией Ti.
Для реализации такого поведения используются три типа блокировок:
-
RL (Read Lock) – в этом режиме блокируется любой объект базы данных o перед выполнением операции чтения его текущей версии; удержание этой блокировки до конца транзакции гарантирует, что при повторном чтении объекта o будет прочитана та же версия этого объекта;
-
WL (Write Lock) – в этом режиме блокируется любой объект базы данных o перед выполнением операции, приводящей к созданию новой (незафиксированной) версии этого объекта; удержание этой блокировки до конца транзакции гарантирует, что в любой момент времени будет существовать не более одной незафиксированной версии любого объекта базы данных;
-
CL (Commit Lock) – блокировка устанавливается во время выполнения операции COMMIT транзакции и затрагивает любой объект базы данных, новую версию которого создала данная транзакция; удовлетворение этой блокировки для данной транзакции гарантирует, что завершились все транзакции, читавшие текущие версии объектов, новые версии которых были созданы при выполнении данной транзакции, и, следовательно, их можно заменить.
В таб. 13.3 показаны правила совместимости этих блокировок.
Таблица 9.3. Таблица совместимости «версионных» блокировок
| RL(o) | WL(o) | CL(o) |
RL(o) | да | да | нет |
WL(o) | да | нет | нет |
CL(o) | нет | нет | нет |
Как видно, операция чтения может блокироваться только на время фиксации транзакции, заменяющей текущую версию требуемого объекта базы данных. Для выполнения операции записи требуется долговременная монопольная блокировка соответствующего объекта базы данных, которая, однако, в этом случае совместима с блокировкой этого же объекта по чтению (поскольку в действительности блокируются разные версии этого объекта). И, конечно, как и во всех схемах сериализации транзакций на основе блокировок, здесь возможны синхронизационные тупики.
Версионно-блокировочный протокол сериализации транзакций для поддержки только читающих транзакций
В заключение обсудим гибридный протокол, поддерживающий эффективное выполнение транзакций, не изменяющих состояние базы данных (Multiversion Protocol for Read-Only Transactions, ROMV). При применении этого протокола при образовании каждой транзакции явно указывается ее тип – только читающая (read-only) или изменяющая (update) транзакция. В только читающих транзакциях допускается использование только операций чтения объектов базы данных, а в изменяющих транзакциях – операций и чтения, и записи.
Изменяющие транзакции выполняются в соответствии с обычным протоколом 2PL, т.е. перед выполнением операции чтения или записи объекта базы данных o этот объект должен быть заблокирован в режиме S или X соответственно, и блокировки объектов удерживаются до конца изменяющей транзакции. Каждая операции записи объекта o создает его новую версию, которая при завершении транзакции помечается временной меткой, соответствующей моменту фиксации этой транзакции.
Каждая только читающая транзакция при своем образовании получает соответствующую временную метку. При выполнении операции чтения объекта базы данных o транзакция получает доступ к версии объекта o, образованной изменяющей транзакцией, которая хронологически последней зафиксировалась к моменту образования данной читающей транзакции.
Основным плюсом протокола ROMV по сравнению с ранее описанным протоколом 2V2PL является принципиальное отсутствие синхронизационных задержек при выполнении операций чтения только читающих транзакций. Если сравнивать ROMV с MVTO, то он выигрывает в принципиальном отсутствии откатов только читающих транзакций. Конечно, при работе изменяющих транзакций возможно возникновение синхронизационных тупиков и откатов, и здесь требуется использовать обычные методы распознавания и разрушения тупиков.
Кроме того, при использовании протокола ROMV в базе данных может возникать произвольное число версий объектов. Требуется создание специального сборщика мусора, который должен удалять ненужные версии данных. Простейший сборщик мусора удаляет все неиспользуемые версии, значения временных меток которых меньше значения временной метки старейшей активной только читающей транзакции.
13.4. Заключение
В этой лекции описаны основные принципы управления транзакциями в системах управления базами данных, различные методы, алгоритмы и протоколы, способствующие достижению целей управления транзакциями. Следует заметить, что существует достаточно развитая теория управления транзакциями с собственными средствами формализации постановки задач и доказательства корректности алгоритмов. Для обеспечения более простого понимания сути материала в него не включены все эти формализмы.
В лекции описаны два основных подхода к сериализации транзакций – на основе синхронизационных блокировок и временных меток. У каждого из этих подходов имеются свои достоинства и недостатки, но на практике существенно больше распространен метод синхронизационных блокировок. В заключение лекции были рассмотрены расширения этих подходов с применением версий объектов базы данных. Соответствующие алгоритмы и протоколы позволяют уменьшить число потенциальных конфликтов транзакций, но для их поддержки требуются дополнительные расходы внешней памяти и усложнение общей архитектуры СУБД.
Лекция 14. Средства журнализации и восстановления баз данных
14.1. Введение
Одним из основных требований к развитым СУБД является надежность хранения баз данных. Это требование предполагает, в частности, возможность восстановления согласованного состояния базы данных после любого рода аппаратных и программных сбоев. Очевидно, что для выполнения восстановлений необходима некоторая дополнительная информация. В подавляющем большинстве современных реляционных СУБД такая избыточная дополнительная информация поддерживается в виде журнала изменений базы данных.
Итак, общей целью журнализации изменений баз данных является обеспечение возможности восстановления согласованного состояния базы данных после любого сбоя. Поскольку основой поддержания целостного состояния базы данных является механизм транзакций, журнализация и восстановление тесно связаны с понятием транзакции. Общими принципами восстановления являются следующие:
-
результаты зафиксированных транзакций должны быть сохранены в восстановленном состоянии базы данных (т.е. должно поддерживаться свойство долговечности (durability) транзакций);
-
результаты незафиксированных транзакций должны отсутствовать в восстановленном состоянии базы данных (в противном случае состояние базы данных могло бы оказаться не целостным).
Это, собственно, и означает, что восстанавливается последнее по времени согласованное состояние базы данных.
Возможны следующие ситуации, при которых требуется производить восстановление состояния базы данных:
-
Индивидуальный откат транзакции. Тривиальной ситуацией отката транзакции является ее явное завершение оператором ROLLBACK. Возможны также ситуации, когда откат транзакции инициируется системой. Примерами могут быть возникновение исключительной ситуации в прикладной программе (например, деление на ноль) или выбор транзакции в качестве жертвы при разрушении синхронизационного тупика. Для восстановления согласованного состояния базы данных при индивидуальном откате транзакции нужно устранить последствия операторов модификации базы данных, которые выполнялись в этой транзакции.
-
Восстановление после внезапной потери содержимого оперативной памяти (мягкий сбой). Такая ситуация может возникнуть при аварийном выключении электрического питания, при возникновении неустранимого сбоя процессора (например, срабатывании контроля основной памяти) и т.д. Ситуация характеризуется потерей той части базы данных, которая к моменту сбоя содержалась в буферах оперативной памяти СУБД.
-
Восстановление после поломки основного внешнего носителя базы данных (жесткий сбой). Эта ситуация при достаточно высокой надежности современных устройств внешней памяти может возникать сравнительно редко, но, тем не менее, СУБД должна быть в состоянии восстановить базу данных даже и в этом случае. Основой восстановления является архивная копия и журнал изменений базы данных.
Во всех трех случаях основой восстановления является хранение избыточных данных. Эти избыточные данные хранятся в журнале, содержащем последовательность записей об изменении базы данных.
Возможны два основных варианта ведения журнальной информации. В первом варианте для каждой транзакции поддерживается отдельный локальный журнал изменений базы данных этой транзакцией. Эти локальные журналы используются для индивидуальных откатов транзакций и могут поддерживаться в основной (правильнее сказать, в виртуальной) памяти СУБД. Кроме того, поддерживается общий журнал изменений базы данных, используемый для восстановления состояния базы данных после мягких и жестких сбоев.