Esse documento e uma traducao de um capitulo de um livro no qual a fonte foi citada no final do documento. Vejo que muitas pessoas detem duvidas em relacao a Point-in-time recovery , essa e minha forma de contribuicao com a comunidade Postgresql. Desculpem pela falta de acentuacao no documento(traduzi o documento ontem as 11/04/2006 01:30 AM ,nao me preocupei muito com a estetica :P ) por qualquer falha de traducao, acho que nao sao muitas e nao poe em risco o bom entendimento. 

Point-in-time recovery

Quando voce faz uma mudanca em algum banco de dados do Postgresql, Postgresql grava suas mudancas no shared-buffer pool, o write ahead log(WAL) e eventualmente no arquivo que voce mudou. O WAL contem registros completos das mudancas que voce fez. O mecanismo de Point-in-time recovery usa um historico de modificacoes  gravados nos arquivos WAL. Imaginne o PITR como um esquema de backup incremental. Voce comeca com um backup completo e depois, arquiva as mudancas realizadas. Quando ocorrer um crash no seu server, voce restora o backup completo(full backup) e aplica as mudancas, em sequencia, ate que se recupere todos os dados que desejas recuperar.

Point-in-time recovery(PITR) pode parecer muito intimidador se voce comeca a ler a documentacao. Para voce ter uma boa visao sobre o sistema de PITR, iremos criar uma nova base, da um crash nela e recuperar os dados usando o mecanismo de PITR. Voce pode seguir se quiser, mas voce ira precisar de um spaco em disco extra.

Iremos comecar criando um novo cluster.
$export PGDATA=/usr/local/pgPITR
initdb

The files belonging to this database system will be owned by user "pg".
This user must also own the server process.
...
Success. You can now start the database server using:

    postmaster -D /usr/local/pgPITR/data
or
    pg_ctl -D /usr/local/pgPITR/data -l logfile start

Agora iremos mudar o arquivo $PGDATA/postgresql.conf para acionar o mecanismo de PITR. A unica mudanca que voce deve fazer e definir o parametro archive_command. O parametro archive_command diz ao Postgresql como os arquivos de WAL(write-ahead-log) irao ser gerados pelo servidor. Tomemos como exempo a seguinte configuracao:
archive_command='cp %p /tmp/wals/%f '
Postgresql ira executar o archive_command ao inves de simplesmente deletar os arquivos WAL como ele normalmente faz. %p significa o caminho completo do WAL  e o  %f  e o nome do arquivo.
Agora iremos criar o diretorio /tmp/wals, startar o processo postmaster e criar um banco de dados para que possamos trabalhar.
$mkdir /tmp/wals
$pg_ctl -l /tmp/pg.log start
$createdb teste
CREATE DATABASE

Nesse momento eu tenho um cluster completo , os dados relativos ao cluster estao em $PGDATA, e um banco de dados chamado teste. Quando eu realizo mudancas no meu banco de dados teste, essas mudancas sao gravados nos arquivos WAL que estao em $PGDATA/pg_xlog(como em qualquer outro  cluster). Quando um arquivo WAL cresce, Postgresql ira copiar ele para o diretorio /tmp/wals para mante-los sao e salvos. A unica diferenca entre um cluster  convencional e um cluster que esteja com o mecanismo de PITR acionado e que o servidor Postgresql ira arquivar os arquivos WAL ao inves de deleta-los.

Como o mecanismo de PITR trabalha com as mudancas efetudas no banco de dados e gravadas nos arquivos WAL, iremos gerar alguns arquivos WAL criando algumas tabelas. Nao interessa o que dados irao conter as tabelas, nos queremos somente gerar os arquivos WAL, ate que eles crescam( cada arquivo WAL contem 16 megas).
$psql
Welcome to psql 8.0.0, the PostgreSQL interactive terminal. ... 
teste=# BEGIN WORK; /* aqui comecamos a nossa transacao*/
teste=# create table teste1 as select * from pg_class,pg_attribute;
SELECT
teste=# COMMIT; executed at 12:30:00 pm /*terminamos a nossa transacao*/
teste=#\q
O commando create table produz uma tabela que contem mais de 245000 registros e produz bastante arquivos WAL capas de chegar aos 16 megas cada um. Voce pode ver os segmentos WAL olhando o diretorio /tmp/wals
$ls /tmp/walls
000000010000000000000000 
000000010000000000000001 
000000010000000000000002
 000000010000000000000003 
000000010000000000000004
Agora iremos criar um backup completo de todo os meus dados do meu cluster. Para simplificar o exemplo irei criar um arquivo .tar.gz e salva-lo no diretorio /tmp. Antes de eu comecar o meu backup, iremos dizer ao Postgresql o que estamos prestes a fazer chamando a funcao pg_start_backup()
$psql teste
Welcome to psql 8.0.0, the PostgreSQL interactive terminal. ... 
teste=# select pg_start_backup('full baclup-Segunda');
pg_start_backup
 ----------------
 0/52EA2B8 (1 row)
 teste=# \q
Agora iremos criar o backup dos nossos dados do cluster
tar czvf /tmp/pgdata.tar.gz $PGDATA
O argumento que demos ao funcao pg_start_backup() e simplesmete um rotulo que ajuda a lembrarmos de onde os arquivos vieram. Voce ire achar o seguinte arquivo $PGDATA/backup_label depois de chamar a funcao, e o rotulo que passamos como parametro estara dentro desse arquivo.
Quando terminarmos de criar o nosso backup, no caso o nosso tarball, iremos dizer ao Postgresql que terminanos chamando a funcao pg_stop_backup()
$psql teste
Welcome to psql 8.0.0, the PostgreSQL interactive terminal. ...
 teste=# select pg_stop_backup();
 pg_stop_backup 
--------------
 0/52EA2F4 (1 row) 
teste=# \q 
Nesse ponto temos um backup completo de todo o nosso cluster, Postgresql continuar rodando( nao paramos o processo postmaster), qualquer mudanca sera gravada nos arquivos WAL, e eles continuam a serem gravados no diretorio /tmp/wals.

**Note que temos um backup completo e no nosso backup temos somente 1 tabela criada.
 Iremos gerar mais arquivos WAL, irei criar outra tabela demonstrativa.
$ psql teste
Welcome to psql 8.0.0, the PostgreSQL interactive terminal.
...
teste=# BEGIN WORK;
BEGIN
teste=# CREATE TABLE teste2 AS SELECT * FROM pg_class, pg_attribute;
SELECT
teste=# COMMIT;  executed at 12:38:00pm
Agora, so para as coisas ficarem mais interessantes criaremos uma terceira tabela e droparemos ela. Esperamos que ela desapareca quando tentarmos recuperar os dados.
$ psql teste
Welcome to psql 8.0.0, the PostgreSQL interactive terminal.
...
teste=# BEGIN WORK;
BEGIN
test=# CREATE TABLE teste3 AS SELECT * FROM pg_class, pg_attribute;
SELECT
test=# COMMIT;  executed at 12:38:00pm
teste=#BEGIN WORK;
BEGIN
teste=# DROP TABLE teste3;
DROP TABLE
teste=# COMMIT; executed at 12:40:00 pm
COMMIT
teste=#\q

Como esperavamos, Postgresql copiou varios arquivos WAL para o diretorio /tmp/wals
$ls /tmp/wals
000000010000000000000000
000000010000000000000001
000000010000000000000002
000000010000000000000003
000000010000000000000004
000000010000000000000005
000000010000000000000005.002EA2B8.backup
000000010000000000000006
000000010000000000000007
000000010000000000000008
000000010000000000000009
00000001000000000000000A
00000001000000000000000B
00000001000000000000000C
00000001000000000000000D
00000001000000000000000E

Nesse ponto acontece um disastre, a energia cai, um furacao inesperado, ou meu computador pega fogo( tudo acontece, arrastao, mensalao e tals menos o meu diretorio /tmp e destroido) para simular um disastre iremos da um kill no processo postmaster.
$KILL -9 (head -1 $PGDATA/postmaster.pid)
Agora e hora de recuperarmos todo o nosso cluster. Comecaremos por renomear o nosso cluster detonado.
$ mv $PGDATA $PGDATA.old
Agora iremos restorar o backup da nossa tarball
$ cp /tmp/pgdata.tar.gz $PGDATA
$ tar -xzvf pgdata.tar.gz

agora temos o nosso $PGDATA.old( que e o diretorio dos arquivos do nosso cluster detonado) e o backup do nosso cluster antigo no $PGDATA. Iremos da uma limpada no cluster restaurado do backup antigo removendo arquivos WAL antigos e o aquivo postmaster.pid
$ rm -rf $PGDATA/pg_xlog/0*
$ rm -rf $PGDATA/postmaster.pid
Para garantir que posso recuperar a maior quantidade de dados possiveis irei copiar os arquivos WAL do cluster danificado dentro do diretorio do cluster restaurado
$cp %PGDATA.old/pg_xlog/0*       $PGDATA/pg_xlog/
Se os arquivos do cluster danificado nao estiverem ao nosso alcance( podem ter queimado quando o computador pegou fogo), podemos recuperar todas as transacoes comitadas antes dos mais recentes arquivos WALs que foram criados. Em um banco de dados com muitas transacoes, perderiamos apenas alguns minutos, cerca de 16 megas.
Agora iremos comecar o processo de recuperacao , mas antes devemos nos lembrar do que aconteceu...

12:30:00pm criamos a tabela teste1  and commitamos as mudancas
2:38:00pm criamos a tabela teste2  and commitamos as mudancas
12:39:00pm criamos a tabela teste3  and commitamos as mudancas
12:40:00pm dropamos a tabela teste3  and commitamos as mudancas
Algum tempo entre 12:30 e 12:38 nos realizamos o backup de todo o banco. (lembre-se que nosso backup fisico so continha a tabela teste1).
Quando iniciamo o processo de recuperacao, podemos recuperar todas as mudancas ou podemos dizer ao Postgresql para parar em certo ponto do tempo(Point in time). Se a recuperacao parar antes de 12:38, so teremos a tabela teste1, nao teremos a tabela teste2 nem a teste3. Se a recuperacao parar antes de 12:39, deveremos ter as tabelas teste1, teste3, mas nao teremos a teste3. Se a recuperacao parar antes de 12:40 teremos as 3 tabelas. Se deixarmos o Postgresql recuperar todas as mudancas a tabela teste3 deve desaparecer, porque dropamos ela.
para controlarmos o processo de recuperacao , criaremos um arquivo chamado $PGDATA/recovery.conf que diz ao Postgresql como proceder. O arquivo recovery.conf se parace com isso:
$ cat $PGDATA/recovery.conf
restore_command= 'cp /tmp/walls/%f %p'
recovery_target_time='2005-06-22 12:39:01 EST'
O parametro restore_command diz ao postgresql como recuperar os arquivos WAL que estao armazenados em /tmp/wals. O parametro recovery_target_time diz ao Postgreql quando parar.Se voce quer recuperar todas as mudancas simplesmente omita esse parametro. Como dizemos ao postgresql para parar em 12:39 irmos encontrar as tabelas teste1,teste2,teste3.
Postgresql comeca o processo de recuperacao logo que o processo postmaster e startado( postmaster sabe que tem algo a fazer porque ele acha o arquivo $PGDATA/recovery.conf
$pg_ctl -l /tmp/pg.log start
postmaster started
Se voce estiver rodando linux/Unix voce pode observar o arquivo de log do servidor
$ tail -f /tmp/pg.log
LOG:  starting archive recovery
LOG:  restore_command = "cp /tmp/wals/%f %p"
LOG:  recovery_target_time = 2005-06-22 13:05:00-05
...
LOG:  restored log file "000000010000000000000006" from archive
LOG:  restored log file "000000010000000000000007" from archive
LOG:  restored log file "000000010000000000000008" from archive
LOG:  restored log file "000000010000000000000009" from archive
...
LOG:  archive recovery complete
LOG:  database system is ready

Quando o processo de recuperacao se completa, Postgresql renomeiao arquivo recovery.conf para recovery.done, para evitar que quando o processo postmaster seja iniciado novamente ocorra de novo a restauracao.
Agora posso me conectar ao meu servidor e ver as tabelas teste1,teste2,teste3.
$psql teste
Welcome to psql 8.0.0, the PostgreSQL interactive terminal. ... 
test=# \d
Como voce pode ver PITR e facil de configurar( somente definir o archive_commando no postgresql.conf.
Recapitulando todo o processo de configuracao:
1- configure o PITR definindo o archive_command no postgresql.conf
2- Restart o postmaster para habilitar o processamento do arquivo WAL
3- conecte em uma database e chame a funcao pg_start_backup(rotulo)
4- Faca o backup do cluster(Voce nao precisa parar o servidor) 
Recapitulando o processo de recuperacao
1- Se possivel renomeie o cluster danificado para que possa copiar a maior quantidade de arquivos wal possiveis
2- Descompacte o cluster do arquivo que foi criado o backup
3- No diretorio do cluster restaurado remova os seguintes arquivos $PG_DATA/pg_xlog/0* e o $PGDATA/postmaster.pid
4- Se possivel copie os arquivos WAL do cluster danificado para o cluster restaurado para garantir que as transacoes mais recentes sejam tambem recuperadas
5- Crie o arquivo recovery.conf, com no minimo o seguinte parametro restore_command
6- Start o postmaster
7- Verifique se os dados que vc esperavam se encontram no lugar

Fonte: PostgreSQL: The comprehensive guide to building, programming, and administering PostgreSQL databases, Second Edition By Korry Douglas, Susan Douglas
Traducao: Joao Cosme de Oliveira Junior : joaocosme@pop.com.br