вторник, 19 марта 2019 г.

Различие транзакций в MiniM и в Cache

При разработке приложений использующих транзакции и при их переносе разработчики должны понимать механизм их работы. Эта статья описывает различие в механизмах транзакционности серверов MiniM и Cache.

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

Откат транзакции формально подразумевает восстановление данных, измененных в транзакции, в их первоначальное состояние. Сервер MiniM Database Server полностью следует этому определению. При работе процессов все сделанные в глобалах изменения записываются в журнал. При коммите транзакции эти журнальные записи более не требуются иначе как для восстановления из бекапа. При откате транзакции сервер просматривает журнальные записи включая записи еще не записанные на диск (в кеше журнала) и возвращает глобалы в исходное состояние, которое было перед их изменением этой транзакцией.

При откате транзакции сервер MiniM просматривает все журнальные записи выполненные транзакцией до самого ее начала. При этом количество сделанных изменений и их тип не имеет значения, все они будут откатываться, и сервер не налагает каких-либо ограничений (исключение составляют записи создаваемые функцией $increment(), эти записи не откатываются никогда).

В этом состоит первое отличие серверов MiniM Database Server и Cache. В отличие от MiniM, Cache может выполнить лишь ограниченное количество откатов удаления из глобалов для команды kill если эта команда вызывает также удаление вложенных подузлов. В случае если транзакция выполнит удалений более чем может откатить Cache, часть удалений не будет восстановлена. Поэтому проектировщик приложений для Cache должен учитывать, в каком режиме и какое количество удалений будет выполнять его программа. В этой же ситуации MiniM Database Server откатывает все сделанные в транзакции изменений.

Пример выполнения операций в Cache:
USER>k ^b s ^b=100000
 
USER>f i=1:1:^b s ^b(i)=1
 
USER>ts
 
USER>f i=1:1:^b k ^b(i)
 
USER>tro
 
USER>w $o(^b("")),!,$o(^b(""),-1),!
1
100000
 
USER>ts  k ^b tro
 
USER>w $o(^b("")),!,$o(^b(""),-1),!
1
1000
Те же операции при выполнении в MiniM:
USER>k ^b s ^b=100000

USER>f i=1:1:^b s ^b(i)=1

USER>ts

USER>f i=1:1:^b k ^b(i)

USER>tro

USER>w $o(^b("")),!,$o(^b(""),-1),!
1
100000

USER>ts  k ^b tro

USER>w $o(^b("")),!,$o(^b(""),-1),!
1
100000
Здесь видно что при выполнении k ^b в транзакции сервер Cache смог откатить лишь часть сделанных удалений, а сервер MiniM выполнил полный откат по всем сделанным изменениям.

MiniM Database Server выполняет откат изменений глобала в состояние, которое было на момент изменения глобала, а не на момент начала транзакции, то есть откатывает именно операции выполненние процессом.

При выполнении отката MiniM Database Server не обращает внимание, было ли изменение данных которые ему нужно вернуть, другим процессом, и все сделанные в транзакции изменения возвращаются в любом случае.

Для примера используем два процесса и последовательность выполнения операций в них в Cache:
Первый процесс                        Второй процесс

USER>k ^b
 
USER>ts
 
USER>s ^b(1)=1,s ^b(2)=2

                                      USER>s ^b(2)=22
 
USER>tro
 
USER>zw ^b
^b(2)=22
Те же операции при выполнении в MiniM:
Первый процесс                        Второй процесс

USER>k ^b

USER>ts

USER>s ^b(1)=1,^b(2)=2

                                      USER>s ^b(2)=22

USER>tro

USER>zw ^b
Здесь видно что сервер MiniM откатил сделанные в транзакции изменения в глобалах независимо от того, было ли изменение этих глобалов в другом процессе.

В данном случае к изменению глобалов относится также операция удаления, или перевод глобального имени в состояние UNDEFINED.

Выполнение кода в Cache с двумя процессами:
Первый процесс                        Второй процесс

USER>k ^a

USER>s ^a(1)=1,^a(2)=2,^a(3)=3

USER>ts

USER>s ^a(2)=22
                                      USER>k ^a

USER>tro
 
USER>zw ^a
 
USER>
Выполнение тех же операций в MiniM:
Первый процесс                        Второй процесс

USER>k ^a

USER>s ^a(1)=1,^a(2)=2,^a(3)=3

USER>ts

USER>s ^a(2)=22
                                      USER>k ^a

USER>tro
 
USER>zw ^a
^a(2)=2

USER>

Здесь в примере видно, что MiniM при откате транзакции обранужил запись в журнале об изменении переменной ^a(2) и восстановил прежнее значение, а сервер Cache принял изменения сделанные во втором процессе и не вернул обратно изменения сделанные в транзакции первым процессом.

Думаю, хорошим вариантом для решения конфликтов доступа будет использование команд блокировок. Обе системы удерживают блокировки выполненные в контексте транзакции до ее окончания.

1 комментарий:

  1. Начиная с Caché 2009.1, kill большого глобала откатывается целиком

    2009.1 под рукой нет, на 2010.2 работает ок:

    USER>k ^b s ^b=100000

    USER>f i=1:1:^b s ^b(i)=1

    USER>ts

    TL1:USER>f i=1:1:^b k ^b(i)

    TL1:USER>tro

    USER>w $o(^b("")),!,$o(^b(""),-1),!
    1
    100000

    USER>ts k ^b tro

    USER>w $o(^b("")),!,$o(^b(""),-1),!
    1
    100000

    USER>w $zv
    Cache for Windows (x86-32) 2010.2.8 (Build 1104_2U) Thu Mar 28 2013 02:42:51 GMTST

    ОтветитьУдалить