прочитавшие текущую версию данных, которую
все транзакции tj, прочитавшие текущую версию данных, которую должна заменить версия, записанная ti (таким образом устраняется возможность неповторяющегося чтения); все транзакции tj, которые записали версии, прочитанные ti (это требуется только во втором варианте алгоритма).
Как видно, этот алгоритм ничего не говорит о числе версий одного и того же элемента, которые могут одновременно существовать в базе данных. Это вызывает проблемы с хранением версий. Во-первых, они могут занимать слишком много места (легко вообразить себе ситуацию, когда объем старых версий становится в несколько раз больше, чем объем всей “текущей” базы данных). Во-вторых, возникают трудности с размещением этих “старых” данных. Учитывая, что количество версий заранее не известно, сложно придумать эффективную структуру их хранения, которая бы не вызывала заметных накладных расходов. И, наконец, такая система слишком сложна в реализации.
Вероятно, именно из-за этих проблем на практике чаще всего используется протокол 2V2PL, предложенный впервые в работе Байера и др.[]. В этом протоколе возможно одновременное существование двух версий элемента данных: одной текущей версии данных и не более одной незавершенной. Такая организация версий выгодна, прежде всего, для транзакций, выполняющих операцию чтения.
В 2V2PL используются три типа блокировок. Каждая блокировка удерживается до конца транзакции.
- rl (read lock): эта блокировка устанавливается на текущую версию элемента данных x непосредственно перед ее прочтением;
- wl (write lock): блокировка устанавливается перед тем, как создать новую (незавершенную) версию элемента x;
- cl (commit lock): блокировка устанавливается перед выполнением последней операции транзакции (обычно перед операцией commit) по отношению к каждому элементу данных, который она записала. Эта блокировка играет роль монопольной блокировки для обычного протокола 2PL. Она необходима для корректной смены версий.
Приведем таблицу совместимости блокировок для 2V2PL:
|
rl(x) |
wl(x) |
cl(x) |
rl(x) |
+ |
+ |
- |
wl(x) |
+ |
- |
- |
cl(x) |
- |
- |
- |
Очевидно, что использование блокировок
rl и
wl обеспечивает выполнение правил (1)a и (1)b алгоритма MV2PL (с учетом того, что одновременно позволяется поддерживать не более одной незавершенной версии). Блокировка
cl, в свою очередь, обеспечивает выполнение правил (2)a и (2)b.
Содержание Назад Вперед