domingo, 15 de abril de 2012

Como resolver problemas com transações Two-Phase-Commit 1/2


Esse artigo sera dividido em duas partes a primeira relatando o problema e possíveis soluções e na segunda parte apresentaremos como remover transações distribuídas usando COMMIT e ROLLBACK force.

A CAUSA

Como resultado de uma falha na confirmação de uma transação distribuída, algumas entradas podem ser gravadas na visão DBA_2PC_PENDING e na DBA_2PC_NEIGHBORS. O evento acontece quando o processo de recover (RECO) verifica essas visões para recuperar a transação que falhou. No entanto, em alguns casos não é possível executar a recuperação. Isso ocorre porque todos os locais que estavam envolvidos na transação não estão mais acessíveis. Outra causa é a visão DBA_2PC_PENDING ficar com transações inconsistentes, que é o tema deste artigo. Essa causa pode ainda ser classificada da seguinte maneira:

1. Entradas na visão DBA_2PC_PENDING para uma transação distribuída inexistente;

2. Há uma transação distribuída para os quais não existem entradas no dba_2pc exibições (inverso do item 1);

3. Como “limpar” (purgar) as transações distribuídas que estão com o “status” como PREPARED. Esse erro ocorre quando uma transação distribuída trava. As visões DBA_2PC_PENDING e DBA_2PC_NEIGHBORS armazenam os detalhes das transações que não foram adequadamente resolvidas.

SOLUÇÕES
Para as entradas na visão DBA_2PC_PENDING sem uma transação correspondente.

Neste caso a visão DBA_2PC_PENDING apresenta as transações distribuídas, mas não há nenhum transação pendente na realidade. Se o “status” da transação for confirmado, a transação pode ser confirmada realizando um “COMMIT FORCE” ou pode-se voltar a transação executando um “ROLLBACK FORCE”. Pode-se utilizar a package “DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY”, para fazer o trabalho.

No entanto, se o “status” da transação está em PREPARED e não há nenhuma entrada na tabela de transação, então esta entrada pode ser limpa manualmente utilizando os passos abaixo:.

SQL> set transaction use rollback segment SYSTEM;
SQL> delete from sys.pending_trans$ where local_tran_id = [valor_local_tran_id];
SQL> delete from sys.pending_sessions$ where local_tran_id = [valor_local_tran_id];

SQL> delete from sys.pending_sub_sessions$ where local_tran_id = [valor_local_tran_id];

SQL> commit;
Exemplo: A consulta a seguir relata uma transação distribuída com o “status” PREPARED.
SQL> select local_tran_id, state from dba_2pc_pending;
LOCAL_TRAN_ID          STATE
---------------------- ----------------
1.92.66874             prepared


Dado que a LOCAL_TRAN_ID é composta por, '1.92.66874' está localizada no segmento de rollback #1 (SYSTEM). Para encontrar a transação que está em execução deve-se utilizar a consulta abaixo:

SQL> SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */,
            KTUXESTA Status, KTUXECFL Flags
       FROM x$ktuxe
      WHERE ktuxesta!='INACTIVE'
        AND ktuxeusn= 1; <== este é o número do segmento de rollback em uso.

no rows selected
Para forçar o “ROLLBACK”, usar:

SQL> rollback force '1.92.66874';
ORA-02058: no prepared transaction found with ID 1.92.66874

Neste caso, não é possível executar o “ROLLBACK FORCE”, então deve-se realizar a limpeza desta transação manualmente:

SQL> set transaction use rollback segment SYSTEM;
SQL>
delete from sys.pending_trans$ where local_tran_id = '1.92.66874';
SQL>
delete from sys.pending_sessions$ where local_tran_id = '1.92.66874';
SQL>
delete from sys.pending_sub_sessions$ where local_tran_id = '1.92.66874';
SQL>
commit;

Em nosso próximo artigo apresentarei a continuação deste assunto…


Rubens Oliveira
DBA Oracle Consultor
olivert.dba@consultant.com

quinta-feira, 5 de abril de 2012

Corrupção física e lógica no Oracle


Este artigo relata um fato vivido recentemente em uma base de dados no mundo real.

Primeiro vamos aos conceitos:

O que é uma corrupção física?

Um bloco pode estar corrompido se o “CHECKSUM” estiver inválido. E quando isso pode ocorrer?

Quando o cabeçalho do bloco estiver inválido - ocorre início do bloco está corrompido com valores inválidos.

Quando o bloco estiver incompleto – ocorre quando as informações do cabeçalho do bloco não correspondem com o restante do bloco (conhecido também como cauda de bloco).

Quando CHECKSUM estiver inválido – o  (CHECKSUM) é calculado pelo processo (DBWR) ou pelo processo (direct loader) antes de gravar o bloco do disco e armazenar o cabeçalho do bloco.

O parâmetro  DB_BLOCK_CHECKSUM pode ser usado para identificar se o bloco foi alterado por algo externo ao banco de dados e também para depois que o bloco foi gravado pela última vez pelo banco de dados. Toda vez que o bloco é lido e se o parâmetro DB_BLOCK_CHECKSUM estiver diferente de FALSE, o banco de dados calcula o CHECKSUM e compara a informação armazenada no cabeçalho do bloco.

Blocos deslocados – ocorrec quando o banco de dados Oracle detecta que o conteúdo do bloco a ser lido pertence a um bloco diferente e o CHECKSUM é válido. A corrupção de blocos físicos, normalmente são relatados como erros ORA-1578 e a descrição detalhada da corrupção é gravada no arquivo do “alert.log”.

O que é uma corrupção lógica?


Quando o bloco contém a verificação do CHECKSUM válida e a estruturado início do bloco está corrompida (o conteúdo do bloco está corrompido).

Corrupções lógicas não são normalmente gravadas no alert.log. O utilitário DBVerify apresenta os blocos que estão logicamente danificados no bloco.

Quando o parâmetro DB_BLOCK_CHECKING está habilitado, ele grava o erro interno ORA-600 [kddummy_blkchk].

Se o parâmetro DB_BLOCK_CHECKING estiver habilitado e o bloco já estiver logicamente corrompido no disco, a próxima atualização do bloco irá marcar o bloco como “Soft Corrupt” e futuras leituras deste bloco irão produzir o erro ORA-1578. Nesse caso o utilitário DBVerify apresenta a corrupção com o erro "DBV-200: Block, dba, already marked corrupted".

Como identificar os segmentos corrompidos no banco de dados?

Para identificar tanto o dano físico como lógico pode usar:

1.   Utilitário RMAN (Recovery Manager) ou;

2.   Utilitário DB Verify – DBV

§  Utilizando o RMAN o paralelismo torna a validação mais rápida, porque utiliza vários canais.

§  Por “default” os backups via RMAN (não possuem a opção de verificação lógica) só existe a detecção de corrupções de bloco físico. 

Abaixo é apresentado o comando que verifica o banco de dados completo para ambas corrupções (lógica ou física) sem realmente executar  uma cópia de segurança

RMAN> configure device type disk parallelism 4;
RMAN> backup validate check logical database;

ou

RMAN> run {
allocate channel diskl1 type disk;
allocate channel disk2 type disk;
allocate channel disk3 type disk;
allocate channel disk4 type disk;
backup validate check logical database;
}


Como identificar corrupção física ou lógica utilizando o utilitário DBVerify?

O utilitário DBVERIFY identifica corrupções físicas e lógicas, porém esse utilitário não pode ser executado no banco de dados inteiro utilizando somente um único comando. Para executá-lo não é necessário conexão com o banco de dados.

Deve-se indicar cada “datafile”, como no exemplo abaixo:

$ dbv file=[caminho+nome_do_datafile]
      blocksize = [tamanho_do_bloco_do_banco_de_dados]


Qual é o melhor? RMAN ou DBV?

  •   O RMAN pode ser executado com a opção de paralelismo, tornando-o mais rápido que o DBV que não pode ser executado em paralelo.
  •   O DBV verifica a existência de blocos vazios. Então levará mais tempo para fazer a varredura de arquivo de dados inteiro.
  •   Na versão do Oracle 10g o RMAN não pode marcar blocos com extensões livres quando estejam configuradas em LMT (Locally Managed Tablespaces).
  •   Na versão do Oracle 11g o RMAN verifica as extensões usadas e livres.
     RMAN> VALIDATE DATAFILE 1 BLOCK 10 to 100;. 

DBV> start=10 end=100

  • O RMAN mantém as informações de corrupção no arquivo de control file (nas visões: v$ database_block_corruption e  v$ backup_corruption). O  DBV não grava as informações de corrupção. As informações podem ser vistas utilizando a consulta abaixo.

    Select * from v$database_block_corruption;

  •  O RMAN não grava detalhes de corrupção como o que exatamente está corrompido em um bloco relatado como uma lógica bloco corrompido.O DBV relata os detalhes de corrupção na tela ou em um arquivo de log.
  • O DBV pode digitalizar blocos com um SCN mais elevado do que um determinado SCN.
  • O DBV não precisa de uma conexão com o banco de dados.

select * from dba_extents
 where file_id = &DATA_FILE_ID
   and &CORRUPTED_BLOCK_ID 
    between block_id AND block_id + blocks - 1;

ou

SELECT e.owner, e.segment_type, e.segment_name, e.partition_name, c.file#
     , greatest(e.block_id, c.block#) corr_start_block#
     , least(e.block_id+e.blocks-1, c.block#+c.blocks-1) corr_end_block#
     , least(e.block_id+e.blocks-1, c.block#+c.blocks-1)
       - greatest(e.block_id, c.block#) + 1 blocks_corrupted
     , null description
  FROM dba_extents e, v$database_block_corruption c
 WHERE e.file_id = c.file#
   AND e.block_id <= c.block# + c.blocks - 1
   AND e.block_id + e.blocks - 1 >= c.block#
UNION
SELECT s.owner, s.segment_type, s.segment_name, s.partition_name, c.file#
     , header_block corr_start_block#
     , header_block corr_end_block#
     , 1 blocks_corrupted
     , 'Segment Header' description
  FROM dba_segments s, v$database_block_corruption c
 WHERE s.header_file = c.file#
   AND s.header_block between c.block# and c.block# + c.blocks - 1
UNION
SELECT null owner, null segment_type, null segment_name, null partition_name, c.file#
     , greatest(f.block_id, c.block#) corr_start_block#
     , least(f.block_id+f.blocks-1, c.block#+c.blocks-1) corr_end_block#
     , least(f.block_id+f.blocks-1, c.block#+c.blocks-1)
       - greatest(f.block_id, c.block#) + 1 blocks_corrupted
     , 'Free Block' description
  FROM dba_free_space f, v$database_block_corruption c
 WHERE f.file_id = c.file#
   AND f.block_id <= c.block# + c.blocks - 1
   AND f.block_id + f.blocks - 1 >= c.block#
order by file#, corr_start_block#;




Rubens Oliveira
DBA Oracle Consultor
olivert.dba@consultant.com