lunedì 20 ottobre 2014

Tabella di Postgres corrotta

Una mattina di sole scopro che ho problemi con una tabella su un database di Postgres, orrore i miei dati sono corrotti, ma la cosa più incredibile è che funziona. Vanno in errore solo le richieste ai record corrotti.
Provo a fare un dump della tabella:

pg_dump: SQL command failedpg_dump: Error message from server: ERROR:  compressed data is corrupt

Niente da fare, facciamo un po di google per trovare una possibile causa:

  1. Problema hardware sui dischi
  2. Problema hardware sulla memoria del server
  3. Sistema instabile
  4. Fsync disabilitato
Oops, vorresti dire che per aumentare le performance avevo disabilitato Fsync.

Ok, almeno non è l'hardware, primo passo riabilito Fsync, fatto.

Adesso devo resuscitare il mio DB.

Per prima cosa creaiamo una bella funzioncina i record scassati:
create function chk(anyelement)
  returns bool
  language plpgsql as $f$
    declare t text;
    begin t := $1;
      return false;
      exception when others then return true;
    end;
  $f$;
Questa funzione alza una eccezione quando non riesce a leggere un record, per cui possiamo utilizzarla per identificare i record errati:

select ctid from mytable where chk(mytable); 
ctid     ------------- (30823,6) (221521,4) (222802,6) (225277,20) (225478,2) (225932,7) (233994,3) (237229,15)(8 rows)
Ok, adesso abbiamo 3 soluzioni:

Cerchiamo di eliminare solo la parte corrotta nel record

Ispezioniamo la tabella e cerchiamo di capire qual'è il campo corrotto, di sicuro è un campo compresso come un tipo text, se lo abbiamo possiamo fare un aggiornamento massivo e annullarne il contenuto.

update mytable set myfield = '' where id in (select id from mytable where chk(mytable ));

Eliminiamo i soli record corrotti

delete from mytable where id in (select id from mytable where chk(mytable ));

O meglio ancora ricreiamo la tabella con solo i record sani

copy (select * from mytable where not chk(mytable )) to '/tmp/mytable .out';
truncate mytable;
copy mytable from '/tmp/mytable .out';

Con questi comandi copiamo la tabella in un file di dump, eliminiamo al tabella e la riceriamo con i dati non corrotti.

Al momento non ho una soluzione per recuperare i dati corrotti, e mi va bene anche perderli, li posso recuperare da un backup.