Manutenção quando registro dá erro

<< Click to Display Table of Contents >>

Navigation:  PostgreSQL > Avançado >

Manutenção quando registro dá erro

Previous pageReturn to chapter overviewNext page

1ª noite

 

Tudo começou com um vacuuming of database “banco” failed: ERROR: invalid page header in block 17850 of relation “tabela”

 

Minha primeira reação foi de espanto quando vi aquilo no e-mail enviado pela Crontab. Aos poucos fui me acalmando e comecei a procurar as razões para aquele comportamento estranho. Olhei os logs do servidor, do banco de dados. Tentei algumas investidas com REINDEX TABLE e com VACUUM mas nada adiantou. (Ah, se o Postgres tivesse REPAIR TABLE…) A resposta era sempre de rejeição:

 

pg_dump: socket not open

pg_dump: SQL command to dump the contents of table “tabela” failed: PQendcopy() failed.

pg_dump: Error message from server: socket not open

pg_dump: The command was: COPY public.tabela (campo1, campo2, campo3, campo4, campo5) TO stdout;

 

Aquilo acendeu uma chama dentro de mim. Quanto mais difícil ficava, mais interesse eu tinha. Quando dei por mim, já estava envolvido demais para deixar de lado.

 

2ª noite

 

A conquista era agora uma questão de honra. Comecei a olhar em fóruns e listas de discussão por dicas de pessoas que já passaram pela mesma situação mas quem realmente me ajudou foi o Tom Lane (integrante do core team de desenvolvimento do Postgresql). Segundo ele, só havia um jeito de resolver:

 

That part sounds more like the table row is corrupted  . 

If you aren’t in a position to restore the whole table from backup, you’ll need to try to identify and wipe out the broken row. 

Usually zeroing its whole page is the easiest way to do this, though you’ll want to see what else is on that page first. 

Check the PG archives for discussions of recovering from corrupted-data scenarios.

 

E assim, me preparei para a grande noite.

 

3ª noite

 

Para alguns, a descrição dos detalhes sórdidos do que aconteceu naquela noite pode ser traumática. Se você se impressiona facilmente, pare de ler por aqui.

Quando cheguei em casa, tratei logo de tirar a roupa. Fiquei só de cueca. Abri um terminal e comecei com um ssh no servidor. Seguindo dicas do pessoal do Pgsql-bugs, peguei o código fonte do pg_dumpfile e compilei. Para tal, precisei do código fonte do Postgres (postgresql-source) e dos headers (postgresql-devel) também. Tive que alterar o Makefile na mão porque não tinha o configure. Feito isso, tratei de verificar se o bloco danificado na página de dados tinha alguma informação crítica.

 

pg_dumpfile -i -d -R 17850 data/base/1777197/1777476

 

O primeiro parâmetro é o bloco com problema. O segundo é o arquivo de dados da tabela que pode ser encontrado com o comando:

 

oid2name -t tabela -d banco

 

Para a minha sorte, não havia nada que não pudesse ser apagado. Então parti para a ação, cortando o mal pela raiz:

 

dd if=/dev/zero of=data/base/1777197/1777476 bs=8k seek=17850 count=1

 

Rezei para que o postmaster não resolvesse escrever nessa tabela no mesmo instante que eu executava o dd, já que, em nenhum momento, parei o servidor postgres. Estava apreensivo com o resultado. Será que deu certo? Vamos fazer uma consulta…

 

SELECT * FROM tabela WHERE ctid='(17850,1)';

——-

(0 rows)

 

Uma resposta sem muita emoção mas que, definitivamente, comprovava a eficácia do método. Para ter certeza de que estava tudo bem, fiz um pg_dump na tabela e … funcionou sem problemas.

 

Naquela noite não consegui dormir direito. Uma mistura de excitação e sensação de dever cumprido.

 

P.S.: Em alguns casos, configurar a variável do Postgres zero_damaged_pages para on e fazer um vacuum ou um dump, resolve o problema de cabeçalho de página inválido. Cuidado! Isso pode causar perda de dados.

 

 

Creditos: Fagner