Ayant rencontré récemment des problèmes de blocs corrompus sur des bases Oracle en version Oracle 10g et Oracle 11g, des différences notables sont apparues notamment au niveau de la vue v$database_block_corruption. Je vous livre dans ce post le résultat de mes tests.
Oracle vérifie l’intégrité des données dans un bloc de base de données avant qu’il soit écrit depuis le buffer cache sur le disque. Si une incohérence de bloc est détectée, alors ce bloc est marqué comme corrompu.

Les corruptions peuvent être de deux types, logiques et physiques :
Les corruptions physiques de blocs peuvent être causées par (liste non exhaustive):

  • disques ou contrôleurs de disques en erreur
  • mémoire défectueuse
  • interface d’entrées/sorties défectueuses (par exemple contrôleur disque défectueux)
  • entrées/sorties OS incomplètes

Dans le cas d’une corruption physique, la base de données ne reconnaît pas du tout le bloc : le checksum est invalide, le header et le footer du bloc ne correspondent pas.
Dans le cas d’une corruption logique le contenu du bloc est logiquement inconsistant. Quand RMAN détecte une corruption logique, il laisse une trace dans le fichier alert.log.
Par défaut RMAN ne vérifie que la corruption physique lors du backup et non la corruption logique. Si l’on souhaite faire une vérification de corruption logique on doit le spécifier en utilisant l’option CHECK LOGICAL.
Si on spécifie l’option CHECK LOGICAL dans la commande backup de RMAN, alors RMAN teste les données ainsi que les indexes et laisse une trace dans le fichier alert.log en cas de corruption.
Sur une base de données Oracle 10g, on effectue les opérations suivantes :
On crée un tablespace:

SQL> create tablespace CORRUPT datafile '/testdba/db01/corrupt01.dbf' size 100M; 
Tablespace created.

On crée un utilisateur hack avec des droits appropriés, une table employe et on y insère des données :

SQL> create user hack identified by hack
2 default tablespace corrupt
3 temporary tablespace temp; 
User created. 
SQL> grant connect , resource ,dba to hack;
Grant succeeded. 
SQL> connect hack/hack
Connected. 
SQL> create table employe (name varchar2(10));
Table created. 
SQL> insert into employe values ('john');
1 row created. 
SQL> insert into employe values ('bill');
1 row created. 
SQL> insert into employe values ('brad');
1 row created. 
SQL> insert into employe values ('joe');
1 row created. 
SQL> commit; 
Commit complete.

Les données sont consistantes :

SQL> select * from employe; 
NAME
----------
john
bill
brad
joe

Puis on corrompt volontairement le fichier physique corrupt01.dbf avec la commande dd:
oracle@l113:~/psi/

[TESTDBA] dd of=/testdba/db01/corrupt01.dbf bs=8192 conv=notrunc seek=12 << EOF
> blahblah blahblah blahblah blahblah blahblah blahblah blahblah blahblah> blahblahiblahblah blahblah
> EOF
0+1 records in
0+1 records out
101 bytes (101 B) copied, 8.8e-05 seconds, 1.1 MB/s

La consultation des données de la table employe nous révèle l’existence de blocs corrompus :

SQL> alter system flush buffer_cache;
 System altered.
SQL> select * from employe;
select * from employe
               *
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 7, block # 12)
ORA-01110: data file 7: '/testdba/db01/corrupt01.dbf'

L’utilisation de RMAN avec l’option «check logical» valide également l’existence des blocs logiques corrompus. RMAN effectue ainsi à la fois une vérification des corruptions logiques et physiques. Par défaut (sans l’option check logical) RMAN détecte uniquement la corruption physique.

RMAN> backup check logical tablespace corrupt;
 
allocated channel: ORA_DISK_1
 
channel ORA_DISK_1: sid=179 devtype=DISK
 
channel ORA_DISK_1: starting full datafile backupset
 
channel ORA_DISK_1: specifying datafile(s) in backupset
 
input datafile fno=00007 name=/testdba/db01/corrupt01.dbf
 
channel ORA_DISK_1: starting piece 1 at 23-SEP-11
 
RMAN-00571: ===========================================================
 
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
 
RMAN-00571: ===========================================================
RMAN-03009: failure of backup command on ORA_DISK_1 channel at 09/23/2011 15:39:00
ORA-19566: exceeded limit of 0 corrupt blocks for file /testdba/db01/corrupt01.dbf

Par contre la vue v$database_block_corruption ne contient aucun enregistrement :
 

SQL> select * from v$database_block_corruption;
no rows selected

Le fichier alert.log est lui aussi correctement renseigné :

Reread of blocknum=12, file=/testdba/db01/corrupt01.dbf. found same corrupt data
Reread of blocknum=12, file=/testdba/db01/corrupt01.dbf. found same corrupt data
Reread of blocknum=12, file=/testdba/db01/corrupt01.dbf. found same corrupt data
Reread of blocknum=12, file=/testdba/db01/corrupt01.dbf. found same corrupt data
Reread of blocknum=12, file=/testdba/db01/corrupt01.dbf. found same corrupt data

Il est nécessaire de lancer rman avec l’option «validate check logical» pour que la vue v$database_block_corruption soit alimentée (cf metalink note id ID 471716.1)

RMAN> backup validate check logical tablespace corrupt;
 
allocated channel: ORA_DISK_1
 
channel ORA_DISK_1: sid=186 devtype=DISK
 
channel ORA_DISK_1: starting full datafile backupset
 
channel ORA_DISK_1: specifying datafile(s) in backupset
 
input datafile fno=00007 name=/testdba/db01/corrupt01.dbf
 
channel ORA_DISK_1: backup set complete, elapsed time: 00:00:01
 
Finished backup at 23-SEP-11
Starting backup at 23-SEP-11
SQL> select * from v$database_block_corruption; 
FILE# BLOCK# BLOCKS CORRUPTION_CHANGE# CORRUPTION
----- ------ ------ ------------------ ----------
    7      12     1                  0    CORRUPT

Nous utilisons la méthode de block recovery pour réparer les blocs corrompus. Il y a bien sur des restrictions pour l’utilisation de cette méthode :

  • la base de données doit être montée ou ouverte
  • on ne peut pas réaliser de block recovery en mode noarchivelog
  • si RMAN n’arrive pas à accéder à une archive de fichier redo log particulière, il réalise un restore failover , essayant d’autres backups disponibles. Si aucun backup n’est disponible, le processus de block recovry via RMAN termine en erreur
  • En version 10g il est nécessaire de posséder un backup full du fichier contenant les blocs corrompus, la méthode de block media recovery ne peut pas utiliser les backups incrémentaux
RMAN> run {
2> allocate channel ch1 type 'sbt_tape';
3> blockrecover corruption list;
4> } allocated channel: ch1
channel ch1: sid=179 devtype=SBT_TAPE
channel ch1: Data Protection for Oracle: version 5.5.2.0 
Starting blockrecover at 23-SEP-11 
channel ch1: restoring block(s)
channel ch1: specifying block(s) to restore from backup set
restoring blocks of datafile 00007
channel ch1: reading from backup piece df_TESTDBA_762622144_23
channel ch1: restored block(s) from backup piece 1
piece handle=df_TESTDBA_762622144_23 tag=TAG20110923T152904
channel ch1: block restore complete, elapsed time: 00:00:16 
starting media recovery
media recovery complete, elapsed time: 00:00:01 
Finished blockrecover at 23-SEP-11released channel: ch1

Les blocs sont maintenant restaurés :

SQL> select * from employe; 
NAME
----
john
bill
brad
joe

Mais la vue v$database_block_corruption contient toujours des données indiquant qu’un bloc est corrompu:

SQL> select * from v$database_block_corruption; 
FILE# BLOCK# BLOCKS CORRUPTION_CHANGE# CORRUPTION
----- ------ ------ ------------------ ----------
    7     12      1                  0    CORRUPT

Il faut relancer un «backup validate check logical» pour que les données de cette vue soient correctes :

RMAN> backup validate check logical tablespace corrupt;
Starting backup at 23-SEP-11
allocated channel: ORA_DISK_1
channel ORA_DISK_1: sid=186 devtype=DISK
channel ORA_DISK_1: starting full datafile backupset
channel ORA_DISK_1: specifying datafile(s) in backupset
input datafile fno=00007 name=/testdba/db01/corrupt01.dbf
channel ORA_DISK_1: backup set complete, elapsed time: 00:00:01
Finished backup at 23-SEP-11
SQL> select * from v$database_block_corruption;
no rows selected

Effectuons à présent les mêmes opérations avec une bases de données Oracle en version 11g.
La commande dd est utilisée pour corrompre les données :

oracle@l113:~/psi/ 

[DORBELV2] dd of=/dorbelv2/db01/data/corrupt01.dbf bs=8192 conv=notrunc seek=131 << EOF
> blahblah blahblah blahblah blahblah blahblah blahblah blahblah blahblah blahblah
> EOF
0+1 records in
0+1 records out
82 bytes (82 B) copied, 6.8e-05 seconds, 1.2 MB/s
SQL> select * from employe;
select * from employe
               *
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 6, block # 131)
ORA-01110: data file 6: '/dorbelv2/db01/data/corrupt01.dbf'

L’interrogation de la vue v$database_block_corruption montre que cette dernière est déjà alimentée , il n’y a plus lieu de lancer rman avec l’option «validate check logical»:

SQL> select * from v$database_block_corruption; 
 
FILE# BLOCK# BLOCKS CORRUPTION_CHANGE# CORRUPTION
----- ------ ------ ------------------ ----------
    6    131      1                   0   CORRUPT

En version 11g on utilise les nouvelles fonctionnalités RMAN pour réparer les blocs corrompus. Il faut bien sûr avant toute opération de restauration analyser quel est le type de segment impacté. Si ce segment est de type index, on peut résoudre le problème rapidement puisque toutes les données nécessaires à la création de l’index sont disponibles. On peut ainsi détruire puis recréer l’index. Si la corruption affecte un tablespace temporaire (temporary tablespace), il est possible de supprimer le tablespace et d’en refaire un nouveau en allouant le nouveau tablespace aux utilisateurs concernés (cf metalink note ID 28814.1)

RMAN> list failure;  List of Database Failures =========================  Failure ID Priority Status Time Detected Summary
---------- -------- --------- ------------- -------
1042 HIGH OPEN 23-SEP-11 Datafile 6: '/dorbelv2/db01/data/corrupt01.dbf' contains one or more corrupt blocks
RMAN> advise failure;
 List of Database Failures
========================= 
Failure ID Priority Status Time Detected Summary
---------- -------- ------ ------------- -------
      1042     HIGH   OPEN     23-SEP-11 Datafile 6: '/dorbelv2/db01/data/corrupt01.dbf' contains one or more corrupt blocks
analyzing automatic repair options;
this may take some time
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=19 device type=DISK
analyzing automatic repair options complete
Mandatory Manual Actions
========================
no manual actions available 
Optional Manual Actions
=======================
no manual actions available
Automated Repair Options
========================
Option Repair Description
------ ------------------
 Perform block media recovery of block 131 in file 6
Strategy: The repair includes complete media recovery with no data loss
Repair script: /dorbelv2/sys01/dump/diag/rdbms/dorbelv2/DORBELV2/hm/reco_3548441823.hm

RMAN> repair failure; Strategy: The repair includes complete media recovery with no data loss Repair script: /dorbelv2/sys01/dump/diag/rdbms/dorbelv2/DORBELV2/hm/reco_3548441823.hm
contents of repair script:
# block media recovery 
recover datafile 6 block 131; 
Do you really want to execute the above repair (enter YES or NO)?
yes
executing repair script
Starting recover at 23-SEP-11
using channel ORA_DISK_1 channel ORA_DISK_1:
restoring block(s)channel ORA_DISK_1:
specifying block(s) to restore from backup set
restoring blocks of datafile 00006
channel ORA_DISK_1: reading from backup piece /mnt/oratmp/df_DORBELV2_762623690_3
channel ORA_DISK_1: piece handle=/mnt/oratmp/df_DORBELV2_762623690_3 tag=TAG20110923T155449channel ORA_DISK_1: restored block(s) from backup piece 1
channel ORA_DISK_1: block restore complete, elapsed time: 00:00:01 
starting media recovery
media recovery complete, elapsed time: 00:00:01
Finished recover at 23-SEP-11
repair failure complete

Les données sont à nouveau correctes :

SQL> select * from employe; 
NAME
----
john
bill
brad
joe

La vue v$database_block_corruption est correctement renseignée sans avoir eu besoin de lancer un backup validate:

SQL> select * from v$database_block_corruption;
no rows selected

Ainsi en version 11g, chaque fois qu”il y a une détection de blocs corrompus la vue v$database_block_corruption est alimentée. Une réparation des blocs corrompus entraine une suppression des méta données de cette vue.
Les différentes techniques de réparation de blocs corrompus incluent les méthodes de block recovery, de restauration de fichiers physiques ou de restauration via un backup incrémental. Cependant bien que la méthode de block recovery puisse réparer les corruptions physiques elle ne peut réparer les corruptions logiques (cf metalink note ID 391120.1)

Conclusion :

La version Oracle 11g a amélioré la gestion de la vue v$database_block_corruption ainsi que la détection des blocs corrompus. De plus l’utilisation des nouvelles fonctionnalités RMAN telles que list, advise ou repair failure permettent un diagnostic et une réparation rapide et efficace.
Je recommanderais par ailleurs l’utilisation systématique de l’option check logical dans les ordres de backup RMAN,. Il y a certes un léger overhead au niveau des temps de sauvegarde, mais il est toujours préférable de détecter les blocs corrompus au plus tôt. Dans ce contexte il peut être également intéressant d’évaluer l’utilisation de l’option DB_BLOCK_CHECKING=YES dans le fichier init.ora ou spfile.ora (cf metalink note ID 32969.1). Bien évidemment avant d’implémenter ces solutions en production il est nécessaire de les tester.
De plus en version 11g, la mise en place d’un script/outil retournant la valeur des données de v$database_block_corruption peut s’avérer nécessaire. En effet ajouter un check des blocs corrompus est intéressant mais il convient d’en être informé rapidement.