In-Memory Database Cache Grid

Ну вот я наконец то добрался до рассмотрения появившегося в TimesTen 11g функционала - In-Memory Database Cache Grid.
Начнем с настройки. В документации процесс создания Cache grid на нескольких машинах описан, на мой взгляд, не досточно четко, поэтому я и решил начать с его конфигурации.

Используемое окружение (три виртуальные машины):

OEL 5.3 (x86) - Oracle Database EE 11.2.0.2.0 – 192.168.2.131 (hostname - db)
OEL 5.3 (x86) - Oracle TimesTen 11.2.1.7.0 (32 bit Linux/x86) – 192.168.2.132 (hostname – tt1)
OEL 5.3 (x86) - Oracle TimesTen 11.2.1.7.0 (32 bit Linux/x86) – 192.168.2.133 (hostname – tt2)

Предварительная настройка для кэш грида, в общем, очень похожа на настройку TimesTen для работы с Oracle Database (об этом можно почитать здесь).




Первоначально, создадим системные объекты и пользователя, с объектами которого будем работать, в Oracle Database.

[oracle@tt1 cache_article]$ sqlplus sys/oracle@orcl as sysdba

SQL*Plus: Release 11.1.0.7.0 - Production on Mon Apr 11 02:57:11 2011

Copyright (c) 1982, 2008, Oracle.  All rights reserved.

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> create tablespace timesten_tbls
  2  /

Tablespace created.

SQL> create user oratt identified by oracle default tablespace timesten_tbls
  2  /

User created.

SQL> grant create session, resource to oratt
  2  /

Grant succeeded.

SQL> create user cacheadmin identified by oracle default tablespace timesten_tbls quota unlimited on timesten_tbls
  2  /

User created.

SQL> @/u01/app/oracle/product/11.2.1/TimesTen/tt1/oraclescripts/initCacheGlobalSchema.sql "timesten_tbls"

Please enter the tablespace where TIMESTEN user is to be created
The value chosen for tablespace is timesten_tbls

******* Creation of TIMESTEN schema and TT_CACHE_ADMIN_ROLE starts *******
1. Creating TIMESTEN schema
2. Creating TIMESTEN.TT_GRIDID table
3. Creating TIMESTEN.TT_GRIDINFO table
4. Creating TT_CACHE_ADMIN_ROLE role
5. Granting privileges to TT_CACHE_ADMIN_ROLE
** Creation of TIMESTEN schema and TT_CACHE_ADMIN_ROLE done successfully **

PL/SQL procedure successfully completed.

SQL> @/u01/app/oracle/product/11.2.1/TimesTen/tt1/oraclescripts/grantCacheAdminPrivileges "cacheadmin"

Please enter the administrator user id
The value chosen for administrator user id is cacheadmin

***************** Initialization for cache admin begins ******************
0. Granting the CREATE SESSION privilege to CACHEADMIN
1. Granting the TT_CACHE_ADMIN_ROLE to CACHEADMIN
2. Granting the DBMS_LOCK package privilege to CACHEADMIN
3. Granting the RESOURCE  privilege to CACHEADMIN
4. Granting the CREATE PROCEDURE  privilege to CACHEADMIN
5. Granting the CREATE ANY TRIGGER  privilege to CACHEADMIN
6. Granting the DBMS_LOB package privilege to CACHEADMIN
7. Granting the SELECT on SYS.ALL_OBJECTS privilege to CACHEADMIN
8. Granting the SELECT on SYS.ALL_SYNONYMS privilege to CACHEADMIN
9. Checking if the cache administrator user has permissions on the default
tablespace
     Permission exists
11. Granting the CREATE ANY TYPE privilege to CACHEADMIN
********* Initialization for cache admin user done successfully *********
SQL>

На этом, настройки в Oracle Database завершены. Преступим к настройкам в TimesTen.

Настройка на узле tt1

Создадим DSN и активируем возможность создания грида. Для этого явно зададим атрибут CachegridEnable( по умолчанию он имеет значение 1).

[db_сache1]
Driver=/u01/app/oracle/product/11.2.1/TimesTen/tt1/lib/libtten.so
DataStore=/u01/app/oracle/datastore/db_cache1
PermSize=100
TempSize=32
PLSQL=1
DatabaseCharacterSet= WE8MSWIN1252
CachegridEnable=1
OracleNetServiceName=ORCL

Создадим необходимых пользователей в TimesTen.

[oracle@tt1 cache_article]$ ttisql db_cache1

Copyright (c) 1996-2010, Oracle.  All rights reserved.
Type ? or "help" for help, type "exit" to quit ttIsql.


connect "DSN=db_cache1";
Connection successful: DSN=db_cache1;UID=oracle;DataStore=/u01/app/oracle/datastore/db_cache1;
DatabaseCharacterSet=WE8MSWIN1252;ConnectionCharacterSet=US7ASCII;
DRIVER=/u01/app/oracle/product/11.2.1/TimesTen/tt1/lib/libtten.so;PermSize=50;TempSize=32;TypeMode=0;OracleNetServiceName=ORCL;
(Default setting AutoCommit=1)
Command> create user cacheadmin identified by oracle;

User created.

Command> grant create session, cache_manager, create any table, drop any table to cacheadmin;

Command> create user oratt identified by oracle;

User created.

Command> grant create session to oratt;
Command>

Далее установим имя и пароль кэш администратора в Oracle Database.

Command> connect "DSN=db_cache1;UID=cacheadmin;PWD=oracle;OraclePWD=oracle";
Connection successful: DSN=db_cache1;UID=cacheadmin;DataStore=/u01/app/oracle/datastore/db_cache1;
DatabaseCharacterSet=WE8MSWIN1252;ConnectionCharacterSet=US7ASCII;DRIVER=/u01/app/oracle/product/11.2.1/TimesTen/tt1/lib/libtten.so;
PermSize=50;TempSize=32;TypeMode=0;OracleNetServiceName=ORCL;
(Default setting AutoCommit=1)
con1: Command> call ttCacheUidPwdSet('cacheadmin','oracle');

Далее, создаем грид и устанавливаем имя грида с datastore. После чего, запускаем кэш агент.

con1: Command> call ttGridCreate('myGrid');
con1: Command> call ttGridInfo;
< MYGRID, CACHEADMIN, Linux Intel x86, 32-bit, 11, 2, 1 >
1 row found.
con1: Command> call ttGridNameSet('myGrid');
con1: Command> call ttCacheStart;

Последний шаг, это "присоединение" узла к гриду.

con1: Command> call ttGridNodeStatus;
0 rows found.
con1: Command> call ttGridAttach(1, 'tt1', 'tt1', 5002);
con1: Command> call ttGridNodeStatus;
< MYGRID, 1, 1, T, tt1, MYGRID_tt1_1, 192.168.2.132, 5002, <null>, <null>, <null>, <null>, <null> >
1 row found.
Command>

Настройка на узле tt2

На втором узле (или любом последующем узле, который вы хотите включить в грид), необходимо выполнить теже действия, что и на узле tt1. Только создавать grid не нужно, т.к. он уже создан.
Выполним эти действия.

[oracle@tt2 cache_article]$ ttisql db_cache2

Copyright (c) 1996-2010, Oracle.  All rights reserved.
Type ? or "help" for help, type "exit" to quit ttIsql.

connect "DSN=db_cache2";
Connection successful: DSN=db_cache2;UID=oracle;DataStore=/u01/app/oracle/datastore/db_cache2;
DatabaseCharacterSet=WE8MSWIN1252;ConnectionCharacterSet=US7ASCII;
DRIVER=/u01/app/oracle/product/11.2.1/TimesTen/tt2/lib/libtten.so;
PermSize=32;TempSize=32;TypeMode=0;PLSQL_TIMEOUT=1000;OracleNetServiceName=ORCL;
(Default setting AutoCommit=1)
Command> create user cacheadmin identified by oracle;

User created.

Command> grant create session, cache_manager, create any table, drop any table to cacheadmin;

Command> create user oratt identified by oracle;

User created.

Command> grant create session to oratt;
Command> connect "DSN=db_cache2;UID=cacheadmin;PWD=oracle;OraclePWD=oracle";
connect "DSN=db_cache2;UID=cacheadmin;PWD=oracle;OraclePWD=oracle";
Connection successful: DSN=db_cache2;UID=cacheadmin;DataStore=/u01/app/oracle/datastore/db_cache2;DatabaseCharacterSet=WE8MSWIN1252;ConnectionCharacterSet=US7ASCII;DRIVER=/u01/app/oracle/product/11.2.1/TimesTen/tt2/lib/libtten.so;
PermSize=32;TempSize=32;TypeMode=0;PLSQL_TIMEOUT=1000;OracleNetServiceName=ORCL;
(Default setting AutoCommit=1)
con1: Command> call ttCacheUidPwdSet('cacheadmin','oracle');
con1: Command> call ttGridInfo;
< MYGRID, CACHEADMIN, Linux Intel x86, 32-bit, 11, 2, 1 >
con1: Command> call ttGridNameSet('myGrid');
con1: Command> call ttCacheStart;
con1: Command>

Далее, подсоединим данный узел к гриду.

Command>  call ttGridNodeStatus;
< MYGRID, 1, 1, T, tt1, MYGRID_tt1_1, 192.168.2.132, 5002, , , , ,  >
1 row found.
Command> call ttGridAttach(1, 'tt2', 'tt2', 5002);
Command> call ttGridNodeStatus;
< MYGRID, 1, 1, T, tt1, MYGRID_tt1_1, 192.168.2.132, 5002, , , , ,  >
< MYGRID, 2, 1, T, tt2, MYGRID_tt2_2, 192.168.2.133, 5002, , , , ,  >
2 rows found.
Command>

На этом конфигурация грида закончена.

Read only Cache Grid

В данном пункте рассмотрим работу Cache Grid с read only кэш группами.

Первоначально создадим таблицу в Oracle Database, которую будем кэшировать, и наполним ее данными.Также предоставим необходимые привилегии кэш администратору.

[oracle@db ~]$ sqlplus oratt/oracle

SQL*Plus: Release 11.2.0.2.0 Production on Mon Apr 18 08:22:13 2011

Copyright (c) 1982, 2010, Oracle.  All rights reserved.

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> create table readtab ( a NUMBER NOT NULL PRIMARY KEY,
2                        b VARCHAR2(100));

Table created.

SQL> select count(*) from readtab;

COUNT(*)
----------
0

SQL> begin
for i in 1 .. 10000  loop
insert into readtab values (i,'db');
end loop;
end;
/
2    3    4    5    6
PL/SQL procedure successfully completed.

SQL> select count(*) from readtab;

COUNT(*)
----------
10000

SQL> grant select on readtab to cacheadmin;

Grant succeeded.

SQL>

Теперь создадим и загрузим кэш группы на узлах tt1 и tt2. Данную команду нужно выполнить на обоих узлах.

Command> CREATE READONLY CACHE GROUP readcache
>    AUTOREFRESH INTERVAL
>    5 SECONDS
>  FROM oratt.readtab ( a NUMBER NOT NULL PRIMARY KEY,
>                       b VARCHAR2(100) );
Command> load cache group readcache commit every 265 rows;
10000 cache instances affected.
Command>

Теперь проверим работу кэш грида.
Для выполнения распределенного запроса, необходимо на уровне сессии установить флаг 'GlobalProcessing' в значение 1. Для этого необходимо воспользоваться функцией ttOptSetFlag. Перед этим необходимо отключить autocommit.

Command> connect "DSN=db_cache1;UID=oratt;PWD=oracle;";
Connection successful: DSN=db_cache1;UID=oratt;DataStore=/u01/app/oracle/datastore/db_cache1;
DatabaseCharacterSet=WE8MSWIN1252;ConnectionCharacterSet=US7ASCII;
DRIVER=/u01/app/oracle/product/11.2.1/TimesTen/tt1/lib/libtten.so;
PermSize=32;TempSize=50;TypeMode=0;PLSQL_TIMEOUT=1000;OracleNetServiceName=ORCL;
(Default setting AutoCommit=1)
Command> select count(*) from readtab;
< 10000 >
1 row found.
Command> set autocommit 0;
Command> call ttOptSetFlag('GlobalProcessing',1);
Command> call ttOptGetFlag('GlobalProcessing');
< GlobalProcessing, 1 >
1 row found.
Command> select count(*) from readtab;
< 20000 >
1 row found.
Command>

Как видим, при выполнени распределенного запроса, объем данных увеличился вдвое, т.е. записи задвоились.Поэтому, если у вас есть TimesTen и вы планируете с помощью Grid увеличить объем read only данных, вы должны учитывать, что при создании read only кэш групп, данные кэшируются не глобально, а локально!!! Т.е. по сути, Grid в для read only КЭШ ГРУПП - это только возможность выполнять глобальные запросы и все. Именно поэтому в определении кэш группы нет ключевого слова global.
Так что данную задачу можно решить, к сожалению, только сегментируя данные.
Например, на уровне создания кэш групп.

Пример.
На одном узле (tt1) выполняем:

Command> CREATE READONLY CACHE GROUP readcache
>    AUTOREFRESH INTERVAL
>    5 SECONDS
>  FROM oratt.readtab ( a NUMBER NOT NULL PRIMARY KEY,
>                       b VARCHAR2(100) )
> where a <= 5000; Command> load cache group readcache commit every 265 rows;
5000 cache instances affected.
Command>

А на другом узле (tt2):

Command> CREATE READONLY CACHE GROUP readcache
>    AUTOREFRESH INTERVAL
>    5 SECONDS
>  FROM oratt.readtab ( a NUMBER NOT NULL PRIMARY KEY,
>                       b VARCHAR2(100) )
> where a >5000;
Command> load cache group readcache commit every 265 rows;
5000 cache instances affected.
Command>

Следовательно, при выполнении глобальных запросов мы увидим все множество:

Command> connect "DSN=db_cache1;UID=oratt;PWD=oracle;";
Connection successful: DSN=db_cache1;UID=oratt;DataStore=/u01/app/oracle/datastore/db_cache1;
DatabaseCharacterSet=WE8MSWIN1252;ConnectionCharacterSet=US7ASCII;
DRIVER=/u01/app/oracle/product/11.2.1/TimesTen/tt1/lib/libtten.so;
PermSize=32;TempSize=50;TypeMode=0;PLSQL_TIMEOUT=1000;OracleNetServiceName=ORCL;
(Default setting AutoCommit=1)
con1: Command>
con1: Command>
con1: Command>
con1: Command> select max(a) from readtab;
< 5000 >
1 row found.
con1: Command> select count(*) from readtab;
< 5000 >
1 row found.
con1: Command> set autocommit 0;
con1: Command> call ttOptSetFlag('GlobalProcessing',1);
con1: Command> call ttOptGetFlag('GlobalProcessing');
< GlobalProcessing, 1 >
1 row found.
con1: Command> select count(*) from readtab;
< 10000 >
1 row found.
con1: Command> select max(a) from readtab;
< 10000 >
1 row found.
con1: Command>

Абсолютно также работают все остальные локальные кэш группы, но у AWT кэш групп есть возможность создания в глобальном режиме. Далее рассмотрим работу AWT кэш групп.

AWT кэш группы в In-Memory DB Cache Grid

C версии 11g при создании AWT кэш групп, можно указать ключевое слово Global,
причем, глобальными могут только AWT кэш группы. Следовательно при указании данного слова, мы говорим о создании распределенного кэша.

Создадим объекты в Oracle DB

[oracle@db ~]$ sqlplus oratt/oracle

SQL*Plus: Release 11.2.0.2.0 Production on Tue Apr 19 06:33:32 2011

Copyright (c) 1982, 2010, Oracle.  All rights reserved.

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> create table awttab ( a NUMBER NOT NULL PRIMARY KEY,
b VARCHAR2(100));
2
Table created.

SQL> begin
for i in 1 .. 100  loop
insert into awttab values (i,'db');
end loop;
end;
2    3    4    5    6  /

PL/SQL procedure successfully completed.

SQL> grant select, insert, update, delete on awttab to cacheadmin;

Grant succeeded.

SQL> select count(*) from awttab;

COUNT(*)
----------
100

SQL>

Создадим AWT кэш группу. Данный код необходимо выполнить на обоих узлах.

Command> create asynchronous writethrough global cache group awtcache
> from oratt.awttab ( a number not null primary key,
>                     b varchar2(100));
Command>
Command> call ttRepStart;
Command>

Инициируем первоначальные данные. Загружаем данные на узле tt2.

Command> dssize;

  PERM_ALLOCATED_SIZE:      32768
  PERM_IN_USE_SIZE:         5867
  PERM_IN_USE_HIGH_WATER:   5867
  TEMP_ALLOCATED_SIZE:      32768
  TEMP_IN_USE_SIZE:         6789
  TEMP_IN_USE_HIGH_WATER:   7351

Command> load cache group awtcache commit every 265 rows;
100 cache instances affected.
Command> dssize;

PERM_ALLOCATED_SIZE:      32768
PERM_IN_USE_SIZE:         5903
PERM_IN_USE_HIGH_WATER:   5903
TEMP_ALLOCATED_SIZE:      32768
TEMP_IN_USE_SIZE:         6800
TEMP_IN_USE_HIGH_WATER:   7351

Command>

Видно, что записи загрузились. Теперь хост tt2 является владельцем данных строк.
Если мы попытаемся загрузить те же записи на узле tt1, то получим ошибку TT3356.

Command> load cache group awtcache commit every 265 rows;
5056: The cache operation fails: error_type=, error_code=<3356>, error_message: [TimesTen]
TT3356: Error loading cache instance from member MYGRID_tt1_1; 
some instance is already owned by some member - from grid member MYGRID_tt2_2
The command failed.
Command>

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

Например:
Узел tt2 содержит 100 строк.

Command> connect "DSN=db_cache2;UID=oratt;PWD=oracle;";
Connection successful: DSN=db_cache2;UID=oratt;DataStore=/u01/app/oracle/datastore/db_cache2;
DatabaseCharacterSet=WE8MSWIN1252;ConnectionCharacterSet=US7ASCII;
DRIVER=/u01/app/oracle/product/11.2.1/TimesTen/tt2/lib/libtten.so;
PermSize=32;TempSize=32;TypeMode=0;PLSQL_TIMEOUT=1000;OracleNetServiceName=ORCL;
(Default setting AutoCommit=1)
Command> select count(*) from awttab;
< 100 >
1 row found.
Command>

На узле tt1 строк нет и выполняя глобальный запрос мы можем получить необходимые строки с узла tt2.

Command> connect "DSN=db_cache1;UID=oratt;PWD=oracle;";
Connection successful: DSN=db_cache1;UID=oratt;DataStore=/u01/app/oracle/datastore/db_cache1;
DatabaseCharacterSet=WE8MSWIN1252;ConnectionCharacterSet=US7ASCII;
DRIVER=/u01/app/oracle/product/11.2.1/TimesTen/tt1/lib/libtten.so;
PermSize=32;TempSize=50;TypeMode=0;PLSQL_TIMEOUT=1000;OracleNetServiceName=ORCL;
(Default setting AutoCommit=1)
Command> select count(*) from awttab;
< 0 >
1 row found.
Command> dssize;

PERM_ALLOCATED_SIZE:      32768
PERM_IN_USE_SIZE:         5867
PERM_IN_USE_HIGH_WATER:   5903
TEMP_ALLOCATED_SIZE:      51200
TEMP_IN_USE_SIZE:         6864
TEMP_IN_USE_HIGH_WATER:   7351

Command> set autocommit 0;
Command> call ttOptSetFlag('GlobalProcessing',1);
Command> call ttOptGetFlag('GlobalProcessing');
< GlobalProcessing, 1 >
1 row found.
Command> select count(*) from awttab;
< 100 >
1 row found.
Command> dssize;

PERM_ALLOCATED_SIZE:      32768
PERM_IN_USE_SIZE:         5867
PERM_IN_USE_HIGH_WATER:   5903
TEMP_ALLOCATED_SIZE:      51200
TEMP_IN_USE_SIZE:         6927
TEMP_IN_USE_HIGH_WATER:   7351


PERM_ALLOCATED_SIZE:      32768
PERM_IN_USE_SIZE:         5903
PERM_IN_USE_HIGH_WATER:   5903
TEMP_ALLOCATED_SIZE:      32768
TEMP_IN_USE_SIZE:         6864
TEMP_IN_USE_HIGH_WATER:   7351

Command>

Кроме того, видно, что при выполнении глобальных операции чтения с удаленных узлов, информация не передается на сторону запрашиваемого узла.

Также, определить, выполняется ли глобальный запрос или нет, можно с помощью просмотра плана выполнения запроса.
Например:
Command> showplan 1;
Command> select count(*) from awttab;

Query Optimizer Plan:

STEP:                1
LEVEL:               1
OPERATION:           RowLkSerialScan
TBLNAME:             AWTTAB
IXNAME:              
INDEXED CONDITION:   
NOT INDEXED:         

< 0 >
1 row found.
Command>

Command> select * from awttab;

Query Optimizer Plan:

STEP:                1
LEVEL:               1
OPERATION:           RowLkTtreeScan
TBLNAME:             AWTTAB
IXNAME:              AWTTAB
INDEXED CONDITION:   
NOT INDEXED:         

0 rows found.
Command> call ttOptSetFlag('GlobalProcessing',1);
Command> call ttOptGetFlag('GlobalProcessing');
< GlobalProcessing, 1 >
1 row found.
Command>  select count(*) from awttab;

Query Optimizer Plan:

STEP:                1
LEVEL:               1
OPERATION:           GridScan
TBLNAME:             
IXNAME:              
INDEXED CONDITION:   
NOT INDEXED:         

< 100 >
1 row found.
Command>

Но ,что будет, если мы попытаемся вставить запись с уже существующим идентификатором на узле tt1.

Command> select * from awttab where a =50;
< 50, db >
1 row found.
Command> insert into awttab values (50,'tt1');
3342: Inserted key already exists on Oracle or remote node
The command failed.
Command>

Как видно, изменения в строках отслеживается на всех узлах грида.
Но, что же будет с изменением данных? Т.е., что будет, если мы попытаемся изменить
данные на одном узле и прочитать с другого.

Например:

Я выполняю update на узле tt2.

Command> set autocommit 0;
Command> update awttab set b='tt2' where a=1;
1 row updated.
Command> select * from awttab where a=1;
< 1, tt2 >
1 row found.
Command>

Конечно, у меня появляется эксклюзивная блокировка на данную строку.
[oracle@tt2 ~]$ ttXactAdmin db_cache2
2011-04-19 07:30:58.367
/u01/app/oracle/datastore/db_cache2
TimesTen Release 11.2.1.7.0

Outstanding locks

PID     Context    TransID     TransStatus Resource  ResourceID           Mode  SqlCmdID   Name

Program File Name: ttIsqlCmd

3754    0x920c740    19.16     Active      Database  0x01312d00           IX    0
Row       BMUFVUAAABcAAAACBA   Xn    34000460   ORATT.AWTTAB                
Table     574836               IXn   34000460   ORATT.AWTTAB

1 outstanding transaction found
[oracle@tt2 ~]$

Пока все отлично, но если я попытаюсь запросить изменяемые данные с другого узла в гриде, я получаю неожиданный результат.
На узле tt1 запрашиваю данные.

Command> call ttOptSetFlag('GlobalProcessing',1);
Command> call ttOptGetFlag('GlobalProcessing');
< GlobalProcessing, 1 >
1 row found.
Command> select * from  awttab where a=1;

Моя сессия подвисает, а на узле tt2 обнаруживаю

[oracle@tt2 ~]$ ttXactAdmin db_cache2
2011-04-19 07:37:38.835
/u01/app/oracle/datastore/db_cache2
TimesTen Release 11.2.1.7.0

Outstanding locks

PID     Context    TransID     TransStatus Resource  ResourceID           Mode  SqlCmdID   Name

Program File Name: ttIsqlCmd

3754    0x920c740    19.18     Active      Database  0x01312d00           IX    0
Row       BMUFVUAAABcAAAACBA   Xn    34000460   ORATT.AWTTAB
Table     574836               IXn   34000460   ORATT.AWTTAB

Program File Name: timestenorad

3775    0xa3ac540    10.4      Active      Database  0x01312d00           IX    0
Table     574836               IXn   0          ORATT.AWTTAB
Row       BMUFVUAAABqAgAAPSU   Xn    0          GRID.AWTTAB_1
Table     574844               IXn   0          GRID.AWTTAB_1

Awaiting locks

PID     Context    TransID     Resource  ResourceID           RMode RSqlCmdID  HolderTransID HMode HSqlCmdID  Name
3775    0xa3ac540    10.4      Row       BMUFVUAAABcAAAACBA   Xn    0            19.18       Xn    34000460   ORATT.AWTTAB
2 outstanding transactions found
[oracle@tt2 ~]$

Неожиданно!!!

Мой простой запрос на узле tt1 инициировал блокировку кэш агента на узле tt2.
Т.е. перед тем как запросить данные, необходимо сбросить изменения в Oracle Database.
Ну и естественно, после таймаута на подвисшей сессии на узле tt1 получил

6003: Lock request denied because of time-out
Details: Tran 10.4 (pid 3775) wants Xn lock on rowid BMUFVUAAABcAAAACBA, table ORATT.AWTTAB. 
But tran 19.18 (pid 3754) has it in Xn (request was Xn). Holder SQL 
(update awttab set b='tt2' where a=1) - from grid member MYGRID_tt2_2
0 rows found.
The command failed.

Процесс 3775 - это pid кэш агента на узле tt2.
Такое поведение кэша стало для меня полной неожиданностью.

Кроме того, изменение данных может проводить, только владелец объекта.
Например, в моем случае, всеми строками в таблице awttab владеет хост tt2 и если я попытаюсь изменить данные через глобальный запрос с узла tt1, то получу ошибку.

Пример:

Узел tt2.
Command> connect "DSN=db_cache2;UID=oratt;PWD=oracle;";
Connection successful: DSN=db_cache2;UID=oratt;DataStore=/u01/app/oracle/datastore/db_cache2;
DatabaseCharacterSet=WE8MSWIN1252;ConnectionCharacterSet=US7ASCII;
DRIVER=/u01/app/oracle/product/11.2.1/TimesTen/tt2/lib/libtten.so;
PermSize=32;TempSize=32;TypeMode=0;PLSQL_TIMEOUT=1000;OracleNetServiceName=ORCL;
(Default setting AutoCommit=1)
Command> select count(*) from awttab;
< 100 >
1 row found.
Command>

Узел tt1.
Command> connect "DSN=db_cache1;UID=oratt;PWD=oracle;";
Connection successful: DSN=db_cache1;UID=oratt;DataStore=/u01/app/oracle/datastore/db_cache1;
DatabaseCharacterSet=WE8MSWIN1252;ConnectionCharacterSet=US7ASCII;
DRIVER=/u01/app/oracle/product/11.2.1/TimesTen/tt1/lib/libtten.so;
PermSize=32;TempSize=50;TypeMode=0;PLSQL_TIMEOUT=1000;OracleNetServiceName=ORCL;
(Default setting AutoCommit=1)
Command> select * from awttab;
0 rows found.
Command>

Теперь попытаемся выполнить изменение строки с узла tt1.
Command> update awttab set b='tt1' where a=30;
805: Global statements other than select and unload has not been implemented
The command failed.
Command>

Как видно, изменения данных может делать только владелец объекта. Но каким образом сделать так, чтобы строки очутились на необходимом узле?
Это можно сделать опять с помощью распределения загружаемых данных или с помощью динамических кэш групп. В TimesTen Cache Grid можно создавать глобальные динамические AWT кэш группы.

Итог

На мой взгляд, данная конфигурация имеет свои плюсы и минусы. К минусам можно отнести неудобство, что на каждом из узлов грида необходимо выполнить одни и теже действия (кроме создания грида), изменение данных может проводить только владелец объектов и самое большое ограничение, на мой взгяд, невозможностью причитать изменяемые данные с разных узлов. Но сама по себе возможность выполнения распределенных запросов является безусловным плюсом данной конфигурации и может достаточно эффективно использоваться с read only данными, ну и конечно, будем надеяться, что в последующих версиях, данные недочеты будут устранены.

Комментариев нет: