Na segunda parte deste
artigo apresentaremos como resolver transações distribuídas que não possuam
entradas correspondentes na visão DBA_2PC_PENDING e como “limpar” transações distribuídas
que estão com status de PREPARED.
SOLUÇÕES
TRANSAÇÕES
DISTRIBUÍDAS SEM ENTRADAS CORRESPONDENTES NA VISÃO DBA_2PC_PENDING
Neste caso as visões
DBA_2PC_PENDING estão vazias, mas os usuários estão recebendo erros
relacionados a transações distribuídas, por exemplo, os erros ORA-2054,
ORA-1591.
Normalmente este caso não
deve aparecer porem caso seja reproduzível pode ser um “BUG”, deve-se após
resolver o problema, verificar no Oracle Support Metalink a atualização de
“patches” para a correção da causa do problema. Abaixo são apresentadas algumas
soluções de contorno:
- Limpar os objetos referenciados por essa transação e importá-las;
- Utilizar o parâmetro “_corrupted_rollback_segments” para descartar o segmento de rollback que esteja com problema;
- Inserir dados fictícios na visão DBA_2PC_PENDING para a execução de “commit ou rollback” (FORCE).
Para a solução 3 deve-se inserir
dados fictícios no dicionário para que a transação possa ser confirmada ou
revertida manualmente.
Observe que o banco de
dados não será capaz de processar esta transação distribuída e o processo (RECO)
deve ser desativado antes de usar este método (deve-se desabilitar o modo de
arquivamento automático “archive log mode”).
Importante: Realizar um BACKUP do seu
banco de dados antes de usar este método.
Transações que ficaram
presas são a causa do erro ORA-01591, por isso a necessidade de limpar essas
entradas, deve-se utilizar a package DBMS_TRANSACTION.
execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('id_da_transacao');
O
exemplo a seguir descreve como diagnosticar e resolver este caso. Suponha que os usuários estão recebendo a mensagem abaixo:
ORA-1591: lock held by in-doubt distributed transaction
1.92.66874.
E a consulta abaixo
não retorne linhas.
SQL> select local_tran_id, state
from
dba_2pc_pending
where local_tran_id='1.92.66874';
no rows selected
where local_tran_id='1.92.66874';
no rows selected
Além
disso, ao consultar o segmento de “undo” é apresentada a transação “1.92.66874” que
está em modo PREPARED.
SQL> SELECT KTUXEUSN, KTUXESLT,
KTUXESQN, /* Transaction ID */
KTUXESTA Status, KTUXECFL Flags
FROM x$ktuxe
WHERE ktuxesta!='INACTIVE'
AND
ktuxeusn= 1; /* <== Substituir este
valor pelo
número do
segmento de rollback
de sua
transação */
SQL> KTUXEUSN
KTUXESLT KTUXESQN STATUS FLAGS
---------- ---------- ---------- ---------------- --------------------
1 92 66874 PREPARED SCO|COL|REV|DEAD
E se realiza uma tentativa de realizar um “commit force” ou
“rollback force” desta transação.
SQL> commit force '1.92.66874';
ORA-02058: no prepared transaction found with ID 1.92.66874
ORA-02058: no prepared transaction found with ID 1.92.66874
O erro ORA-02058 são
gerados porque as visões DBA_2PC_PENDING e DBA_2PC_NEIGHBORS
estão vazias. Para usar o “commit force” ou “rollback force” deve-se inserir um
registro fictício na visão DBA_2PC_PENDING, conforme apresentado abaixo:
SQL>
alter system disable distributed recovery;
SQL>
insert into pending_trans$ ( LOCAL_TRAN_ID, GLOBAL_TRAN_FMT, GLOBAL_ORACLE_ID,
STATE,
STATUS, SESSION_VECTOR, RECO_VECTOR,TYPE#, FAIL_TIME, RECO_TIME)
values(
'1.92.66874', /* Altere o valor de sua
transação local (LOCAL_TRAN_ID) */
306206, /*
*/
'XXXXXXX.12345.1.2.3', /* Esses valores podem ser utilizados sem
qualquer */
'prepared','P', /* modificação. Muitos desses valores
sáo constantes */
hextoraw(
'00000001' ), /*
*/
hextoraw(
'00000000' ), /*
*/
0,
sysdate, sysdate );
SQL>
insert into pending_sessions$
values(
'1.92.66874', /* <==Altere para sua
transação local (LOCAL_TRAN_ID)*/
1,
hextoraw('05004F003A1500000104'), 'C', 0, 30258592, '', 146);
SQL>
commit;
SQL>
commit force '1.92.66874';
Se
a instrução “commit force” gerar um erro, anote a mensagem de erro e execute os
comandos abaixo:
SQL> delete from pending_trans$ where
local_tran_id='1.92.66874';
SQL> delete from pending_sessions$ where
local_tran_id='1.92.66874';
SQL> commit;
SQL> alter system enable distributed recovery;
Caso contrário executar o processo de entrada fictícia do dicionário,
usando:
SQL> alter system enable distributed recovery;
SQL> connect / as sysdba
SQL> COMMIT;
Use
a consulta abaixo para recuperar o valor para do parâmetro “_smu_debug_mod”.
SQL> col Parameter for a20
SQL> col "Session Value" for a20
SQL> col "Instance Value" for a20
SQL> SELECT a.ksppinm
"Parameter",b.ksppstvl "Session Value",
c.ksppstvl
"Instance Value"
FROM
x$ksppi a, x$ksppcv b, x$ksppsv c
WHERE
a.indx = b.indx
AND
a.indx = c.indx
AND a.ksppinm = '_smu_debug_mode';
Configure o parâmetro “_smu_debug_mode” para 4.
SQL> alter system set "_smu_debug_mode" = 4;
/* Configurar com esse
valor se estiver usando
o segmento
de UNDO em modo automático */
A
partir da versão 9.2x o comando “alter session” pode ser utilizado dinamicamente.
SQL> commit; /* Isto é
para evitar o erro ORA-01453 durante a
limpeza
utilizando a package “purge_lost_db_entry” */
SQL> exec dbms_transaction.purge_lost_db_entry(
'1.92.66874' );
SQL> commit;
SQL> alter system set "_smu_debug_mode" =
;
SQL> commit;
COMO LIMPAR UMA TRANSAÇÃO
DISTRIBUÍDA COM “STATUS” PREPARED, QUANDO UM COMMIT OU ROLLBACK FORCE, TRAVAR.
Se a mensagem abaixo for apresentada.
ORA-01591: lock held by in-doubt distributed transaction
44.88.85589
Deve-se verificar
se o registro existe na visão DBA_2PC_PENDING e qual o segmento de “rollback”
está em uso, execuntando o comando abaixo.
SQL> SELECT LOCAL_TRAN_ID,STATE FROM
DBA_2PC_PENDING;
LOCAL_TRAN_ID
STATE
-------------- --------
44.88.85589
prepared
SQL> SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /*
Transaction ID */
KTUXESTA Status, KTUXECFL Flags
FROM
x$ktuxe
WHERE ktuxesta!='INACTIVE'
AND ktuxeusn= 44;
/* <== Alterar o valor para o número da transação
no seu segmento de UNDO que é exibido na
primeira parte do ID da transação */
KTUXEUSN KTUXESLT KTUXESQN
STATUS FLAGS
---------- ---------- ---------- ----------------
------------------------
44
88 85589 PREPARED SCO|COL|REV|DEAD
SQL> Commit force 44.88.85589;
ou
SQL> rollback force 44.88.85589;
Se
ao executar o “COMMIT” ou “ROLLBACK FORCE” e o comando travar, o banco de dados
irá assinalar o evento de espera (wait system events) "free global transaction table entry”.
Para limpar esta transação,
deve-se utilizar a package abaixo:
SQL> EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('44.88.85589');
BEGIN DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('44.88.85589'); END;
*
ERROR at line 1:
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at "SYS.DBMS_TRANSACTION", line 94
ORA-06512: at line 1
BEGIN DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('44.88.85589'); END;
*
ERROR at line 1:
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at "SYS.DBMS_TRANSACTION", line 94
ORA-06512: at line 1
Caso essa mensagem de
erro apareça pode-se executar umas das soluções:
1.
Gerar
entradas de dados nas visões das DBA_2PC_PENDING e DBA_2PC_NEIGHBORS
sem transações
correspondentes;
2.
Gerar
transações distribuídas sem entradas correspondentes nas visões DBA_2PC_PENDING
e DBA_2PC_NEIGHBORS
Para a solução 1, executar os comandos abaixo:
SQL> delete from sys.pending_trans$ where
local_tran_id = '44.88.85589';
SQL> delete from sys.pending_sessions$ where local_tran_id = '44.88.85589';
SQL> delete from sys.pending_sub_sessions$
SQL> delete from sys.pending_sessions$ where local_tran_id = '44.88.85589';
SQL> delete from sys.pending_sub_sessions$
where
local_tran_id ='44.88.85589';
SQL> commit;
SQL> commit;
Para a solução 2, executar os passos abaixo:
Inserir registros fictícios,
como descritos na seção (ver: Transações distribuídas sem entradas
correspondentes na visão DBA_2PC_PENDING). Para transações distribuídas sem
registros correspondentes na visão DBA_2PC_PENDING, executar.
SQL> Commit force '44.88.85589';
Para limpar transações pendentes, usar:
Para limpar transações pendentes, usar:
SQL> exec dbms_transaction.purge_lost_db_entry('44.88.85589');
Para
escrever esse artigo usei como referência a nota da Oracle (Note:126069.1 - Manually Resolving In-Doubt Transactions:
Different Scenario's).
Rubens Oliveira
DBA Oracle Consultor
olivert.dba@consultant.com