Классика баз данных - статьи



         

Трудные классы транзакций


Не для всех транзакций можно запросить блокировки всех записей, к которым в ней будут происходить обращения, сразу после поступления транзакции в систему. Рассмотрим транзакцию

U(x): y ← read(x) write(y)

где x является первичным ключом записи, y – локальная переменная, и write(y) обновляет запись, первичный ключ которой содержится в y.

Очевидно, что для транзакций типа U невозможно запросить блокировки сразу после входа в систему (если только не заблокировать целиком таблицу, связанную с y), поскольку механизм исполнения никаким образом не может определить значение y, не выполнив до этого чтение записи x. Мы называем такие транзакции зависимыми транзакциями (dependent transactions). В нашей схеме проблема зависимых транзакций решается путем их разбиения на несколько транзакций, из которых все транзакции, кроме последней, работают с целью обнаружения полного набора чтения/записи, так что последняя транзакция может начать свое выполнение при наличии полного знания о том, к чему она будет обращаться. Например, транзакцию U можно разбить на транзакции:

U1(x): y ← read(x) newtxnrequest(U2(x, y))

и

U2(x, y): y' ← read(x) if (y' ≠ y) newtxnrequest(U2(x, y')) abort() else write(y)

U2 не включается в упорядоченные пакеты транзакций, направляемые препроцессором в системы, которые содержат реплики, до тех пор, пока в препроцессор не поступит результат U1 (в этот промежуток времени может выполняться произвольное число транзакций). В U2 имеется некоторая информация о том, что, вероятно, следует заблокировать, и соответствующие элементы данных немедленно блокируются. После этого U2 проверяет, что заблокированы корректные элементы данных (т.е. что никакая транзакция, выполнявшаяся в промежуток времени между завершением выполнения U1 и началом выполнения U2 не изменила зависимость). Если эта проверка удается, то выполнение U2 может продолжаться. Иначе U2 должна завершиться аварийным образом (и освободить свои блокировки).


Содержание  Назад  Вперед