Entendendo-PostgreSQL

21
Desmistificando o PostgreSQL - Alterar o Código Fonte de um SGBD é Coisa pra Macho???- 1. O PostgreSQL O PostgreSQL é, em suma, um sistema de gerenciamento de banco de dados objeto-relacional (SGBDOR) desenvolvido com base nos códigos do projeto Postgres, encabeçado e mantido pelo Departamento de Ciência da Computação da Universidade da Califórnia em Berkeley, desde 1985, coordenado pelo professor Michael Stonebraker. Seu grande diferencial consiste em disponibilizar seu código, o que permite que muitos programadores, espalhados por vários países, contribuam para sua evolução constante. O PostgreSQL possui versões tanto para ambientes Unix quanto para Windows; o presente trabalho baseia-se no primeiro, na distribuição Fedora. Atualmente, o PostgreSQL é um dos SGBD de código aberto mais avançado, seus principais recursos são: Consultas complexas. Chaves estrangeiras. Integridade transacional. Controle de concorrência multi-versão. Suporte ao modelo híbrido objeto-relacional. Trigger. Views. Stored procedures em várias linguagens. 2. Histórico O PostgreSQL é um dos resultados de uma ampla evolução que se iniciou com o projeto Ingres, desenvolvido na Universidade de Berkeley, Califórnia. O lider do projeto, Michael Stonebraker, um dos pioneiros dos bancos de dados relacionais, deixou a universidade em 1982 para comercializar o Ingres, porém retornou a ela logo em seguida. Após seu retorno a Berkeley, em 1985, Stonebraker começou um projeto pós-Ingres com o objetivo de resolver problemas com o modelo de banco de dados relacional. O principal problema era a incapacidade do modelo relacional compreender “tipos” (atualmente, chamados de objetos), ou seja, combinações de dados simples que formam uma única unidade. O projeto resultante, chamado Postgres, era orientado a introduzir a menor quantidade possível de funcionalidades para completar o suporte a tipos. Estas funcionalidades incluíam a habilidade de definir tipos, mas também a habilidade de descrever relações - as quais até este momento eram

Transcript of Entendendo-PostgreSQL

Page 1: Entendendo-PostgreSQL

Desmistificando o PostgreSQL

- Alterar o Código Fonte de um SGBD é Coisa pra Macho???- 1. O PostgreSQL

O PostgreSQL é, em suma, um sistema de gerenciamento de banco de dados objeto-relacional (SGBDOR) desenvolvido com base nos códigos do projeto Postgres, encabeçado e mantido pelo Departamento de Ciência da Computação da Universidade da Califórnia em Berkeley, desde 1985, coordenado pelo professor Michael Stonebraker. Seu grande diferencial consiste em disponibilizar seu código, o que permite que muitos programadores, espalhados por vários países, contribuam para sua evolução constante. O PostgreSQL possui versões tanto para ambientes Unix quanto para Windows; o presente trabalho baseia-se no primeiro, na distribuição Fedora.

Atualmente, o PostgreSQL é um dos SGBD de código aberto mais avançado, seus principais recursos são:

• Consultas complexas.

• Chaves estrangeiras.

• Integridade transacional.

• Controle de concorrência multi-versão.

• Suporte ao modelo híbrido objeto-relacional.

• Trigger.

• Views.

• Stored procedures em várias linguagens.

2. Histórico

O PostgreSQL é um dos resultados de uma ampla evolução que se iniciou com o projeto Ingres, desenvolvido na Universidade de Berkeley, Califórnia. O lider do projeto, Michael Stonebraker, um dos pioneiros dos bancos de dados relacionais, deixou a universidade em 1982 para comercializar o Ingres, porém retornou a ela logo em seguida.

Após seu retorno a Berkeley, em 1985, Stonebraker começou um projeto pós-Ingres com o objetivo de resolver problemas com o modelo de banco de dados relacional. O principal problema era a incapacidade do modelo relacional compreender “tipos” (atualmente, chamados de objetos), ou seja, combinações de dados simples que formam uma única unidade.

O projeto resultante, chamado Postgres, era orientado a introduzir a menor quantidade possível de funcionalidades para completar o suporte a tipos. Estas funcionalidades incluíam a habilidade de definir tipos, mas também a habilidade de descrever relações - as quais até este momento eram

Page 2: Entendendo-PostgreSQL

amplamente utilizadas, mas completamente mantidas pelo usuário. No Postgres, o banco de dados "compreendia" as relações e podia obter informações de tabelas relacionadas utilizando regras.

Iniciando em 1986, a equipe divulgou uma série de documentos descrevendo a base do sistema e em 1988 o projeto possuía um protótipo funcional. A versão 1 foi liberada para um grupo pequeno de usuários em junho de 1989, seguida pela versão 2 com um sistema de regras reescrito em junho de 1990. Para a versão 3, liberada em 1991, o sistema de regras foi reescrito novamente, mas também foram adicionados suporte para múltiplos gerenciadores de armazenamento e um melhorado motor de consultas. Já em 1993, Postgres havia crescido imensamente em popularidade e possuía uma grande demanda por suporte e por novas funcionalidades. Após a liberação da versão 4, a qual era uma simples versão de limpeza, o projeto foi oficialmente abandonado pela Universidade de Berkeley.

Entretanto, devido ao fato do seu código fonte estar sob uma licença BSD, o seu desenvolvimento foi continuado. Em 1994, dois estudantes de Berkeley, Andrew Yu e Jolly Chen, adicionaram um interpretador SQL para substituir a linguagem QUEL (desenvolvida para o Ingres) e o projeto foi renomeado para Postgres95. Com a divulgação de seu código pela Internet, Postgres95 iniciou uma nova vida como software open source.

Em agosto de 1996, Marc Fournier, Bruce Momjian e Vadim B. Mikheev lançaram a primeira versão externa da Universidade de Berkeley e deram início à tarefa de estabilizar o código herdado. Também em 1996, o projeto foi renomeado para PostgreSQL a fim de refletir a nova linguagem de consulta ao banco de dados: SQL. A primeira versão de PostgreSQL, a 6.0, foi liberada em janeiro de 1997. Desde então, um grupo de desenvolvedores e de voluntários de todo o mundo, coordenados pela Internet, têm mantido o software e desenvolvido novas funcionalidades.

As principais características acrescentadas nas versões 6.x são o MVCC (Multiversion

Concurrency Control – Controle de Concorrência Multiversões), melhorias no SQL e novos tipos de dados nativos (novos tipos de datas e hora e tipos geométricos).

Em maio de 2000 foi liberada a versão 7.0. As versões 7.x trouxeram as seguintes novas funcionalidades: Write-Ahead Log (WAL), esquemas SQL, outer joins, suporte a IPv6, indexação por texto, suporte melhorado a SSL e informações estatísticas do banco de dados.

A versão 8.0 foi lançada em janeiro de 2005 e entre outras novidades, foi a primeira a ter suporte nativo para Microsoft Windows (tradicionalmente, o PostgreSQL só rodava de forma nativa em sistemas Unix e, em sistemas Windows - através da biblioteca Cygwin). Dentre as muitas novidades da versão 8.x, pode-se destacar o suporte a tablespaces, save points, point-in-time

recovery, roles e Two-Phase Commit (2PC). Em dezembro de 2006 foi lançada a versão mais recente: 8.2.

Desenvolvimento do Projeto

O PostgreSQL é um projeto open source coordenado pelo PostgreSQL Global Development

Group. Embora as atividades do grupo sejam patrocinadas por diversas organizações de todo o mundo, seu modelo de desenvolvimento é o modelo Bazar (originalmente apresentado em A Catedral e o Bazar de Eric S. Raymond).

Portanto, o desenvolvimento do PostgreSQL é feito por um grupo de desenvolvedores, em sua maioria voluntários, espalhados por todo o mundo e que se comunicam via Internet. Logo, trata-se, de um projeto direcionado pela comunidade de desenvolvedores e de usuários, a qual qualquer pessoa pode se juntar, bastando se inscrever em listas de discussão e delas participar.

Voluntários interessados em contribuir com o projeto também podem consultar as sugestões de tarefas de desenvolvimento de novas funções e de correções de erros que são publicadas na lista

Page 3: Entendendo-PostgreSQL

“TODO” ou apresentar suas próprias sugestões. O código desenvolvido é submetido à equipe do projeto que pode aceitá-lo e incluí-lo nas novas versões ou recusá-lo. Voluntários também podem colaborar gerando documentação ou realizando traduções.

As ferramentas utilizadas para o apoio ao desenvolvimento são o sistema de gestão de fontes CVS (Concurrent Version System), listas de discussão, servidor de news e salas de bate-papo (IRC).

Estruturas de Decisão

O Projeto PostgreSQL é desenvolvido e direcionado pela sua comunidade de desenvolvedores e de usuários. Para coordenar o projeto há uma equipe central (core team) composta por sete desenvolvedores e um grupo de committers CVS. O código fornecido por voluntários é avaliado e aceito ou rejeitado pelos committers.

Este modelo de desenvolvimento de software, baseado no modelo Bazar originalmente apresentado em A Catedral e o Bazar de Eric S. Raymond, possibilita o desenvolvimento de software com qualidade devido, principalmente, a permitir:

• Tratar usuários como parceiros e/ou desenvolvedores. Eles contribuem diretamente com o desenvolvimento do software apresentando os problemas enfrentados, suas necessidades, suas sugestões de solução e, até mesmo, seu próprio código fonte de solução. Assim, usuários auxiliam de forma pró-ativa nas melhorias e na depuração do software.

• Reutilizar código fonte.

• Lançar rapidamente e freqüentemente novas versões. Com uma base ampla de usuários testadores do software, os eventuais problemas são rapidamente identificados e sugestões de solução também aparecem com rapidez. Por exemplo, no Projeto PostgreSQL, a versão 8.2.0 foi lançada exatamente 50 dias depois da versão anterior e apresentou 180 acréscimos ou alterações em código fonte implementadas por 71 programadores diferentes.

Estado Atual

Inicialmente desenvolvido na Universidade de Berkeley, Califórnia, a partir de 1996, o PostgreSQL firmou-se como um projeto de software open source desenvolvido por uma comunidade de voluntários sob a coordenação do PostgreSQL Global Development Group.

Além de doações, o projeto PostgreSQL se sustenta pelo patrocínio de diversas empresas, entre as quais se destacam: Fujitsu, Hub.Org, NTT Group, Red Hat, Skype, SRA e Sun Microsystems.

O software tem adquirido prestígio na comunidade Linux, tendo recebido diversas vezes o prêmio Linux Journal Editor's Choice de melhor sistema de gerenciamento de banco de dados (SGBD).

Além da comunidade Linux, a aceitação do PostgreSQL também tem se ampliado. Há entre os seus usuários grandes empresas internacionais, órgãos governamentais de vários países e universidades de prestígio mundial. Uma lista dos principais usuários pode ser vista em www.postgresql.org/about/users. Em www.postgresql.org/about/casestudies podem ser vistos estudos de caso de aplicações do PostgreSQL.

Page 4: Entendendo-PostgreSQL

3. Estrutura dos Arquivos

Diretório Principal:

/etc/postgresql/8.1/main/

Diretório de Executáveis:

/usr/postgresql/lib/8.1/Bin

Diretorio de Dados:

/var/lib/postgresql/8.1/main

/etc/postgresql/8.1/main/pgdata(link)

Diretorio de Log:

/var/log/postgresql/

/etc/postgresql/8.1/main/log(link)

Subdiretórios de pgdata:

• base: bases de dados

• blobal: data acessíveis para todo o cluster

• pg_clog: status das transações

• pg_subtrans: status de sub-transações

• pg_multixact: status de transação para shared row lock

• pg_tblspc: links simbólicos de tablespace

• pg_xlog: arquivos do wal

• pg_twophase: status dos procedimentos preparados.

Page 5: Entendendo-PostgreSQL

4. Arquivos e Pastas Interessantes

backend/parser/keywords.c

backend/parser/gramy .c

backend/parser/analyze.c

include/nodes/parsenodes.h

include/nodes/execnodes.h

backend/catalog/index.c

backend/catalog/indexing.c

include/catalog/pg_index.h

Page 6: Entendendo-PostgreSQL

backend/commands/indexcmds.c

backend/commands/copy.c

include/executor/executor.h

Page 7: Entendendo-PostgreSQL

5. Guia Rápido de Instalação

Esta seção visa apresentar um roteiro simplificado que auxilie o processo de instalação do SGBD PostgreSQL em Linux. Mais detalhes devem ser obtidos na documentação oficial, em http://www.postgresql.org/docs.

3.1 – Obtenção dos fontes

Realize “download” do arquivo compactado possuindo o código fonte do PostgreSQL em: ftp://ftp.postgresql.org/pub/source/v7.4.13/postgresql-7.4.13.tar.gz. Uma vez concluído o processo de cópia, descompacte:

gunzip -c postgresql-7.4.13.tar.gz | tar -xvf –

Esse comando criará o diretório postgresql-7.4.13 sob o diretório corrente. Ele deve ser o corrente daqui em diante.

3.2 – Configuração

Após fazer do diretório postgresql-7.4.13 o diretório corrente, execute o comando:

./configure

O comando acima somente precisa ser executado na fase de instalação, isto é, após alterar o código, não é mais necessário realizar esta etapa de configuração.

Em princípio, os arquivos dos futuros bancos a serem criados vão para /usr/local/pgsql. Isto pode ser alterado da seguinte forma:

./configure --prefix=outro caminho

3.3 – Construção

Concluída a etapa de configuração, deve-se compilar os arquivos fonte. Ainda no diretório postgresql-7.4.13, execute o comando:

make

Cada vez que algum arquivo fonte (extensões .c, .h) sofrer alterações deve-se repetir a etapa de construção executando o comando acima. Se não houver erros de compilação, a última mensagem deve ser esta:

Page 8: Entendendo-PostgreSQL

All of PostgreSQL successfully made. Ready to install.

Para reverter os efeitos desta etapa, deve-se executar o comando:

make clean

3.4 – Instalação

Concluída a etapa de construção, deve-se instalar o PostgreSQL. Ainda no diretório postgresql-7.4.13 , execute o comando:

make install

Caso o usuário corrente não possua plenos direitos para criar arquivos no Servidor em questão, deve-se executar a tarefa acima conectado como root.

Se não houver erros de instalação, a última mensagem deve ser esta:

Thank you for choosing PostgreSQL, the most advanced open source

database engine.

Para reverter os efeitos desta etapa, deve-se executar o comando:

make uninstall

Deve-se ressaltar, entretanto, que, uma vez concluída a primeira instalação e realizadas alterações em arquivos fonte, não é necessário desinstalar o PostgreSQL.

3.5 – Variáveis de ambiente

Para evitar longos caminhos de diretórios em comandos que interajam com PostgreSQL, recomenda-se a criação de algumas variáveis de ambiente:

export LD_LIBRARY_PATH=/usr/local/pgsql/lib

export PATH=/usr/local/pgsql/bin:$PATH

export MANPATH=/usr/local/pgsql/man:$MANPATH

export PGDATA=/usr/local/pgsql/data

Os caminhos de diretórios utilizados devem ser coerentes com a etapa de configuração. Assim, caso tenha-se decidido utilizar outro destino que não o padrão, deve-se substituir /usr/local pelo novo caminho.

Page 9: Entendendo-PostgreSQL

Os comandos acima podem constar em um arquivo que seja executado automaticamente uma vez carregado o Sistema Operacional, como por exemplo, o arquivo /etc/profile. Deve-se garantir, entretanto, que os comandos acima serão executados, pelo menos uma vez, antes de utilizar o PostgreSQL.

Recomenda-se também criar um usuário Linux específico para lidar com PostgreSQL. Geralmente, chama-se postgres.

Para criar o usuário administrador para o postgresql use:

sudo adduser postgres

Em seguida forneça uma senha de acesso para ele.

3.6 – Criação de Bancos de Sistema

Antes de criar Bancos de Dados regulares, deve-se construir o database cluster (grupo de Bancos de Sistema) . Conectado como o usuário Linux responsável pelo PostgreSQL (geralmente postgres) e tendo criado as variáveis de ambiente citadas no item anterior, basta executar o comando:

initdb

Será criado e preenchido o diretório data sob PGDATA (variável de ambiente definida no item 5).

3.6 – Disponibilização

Conexões somente podem acontecer caso o PostgreSQL esteja disponibilizado. Isto ocorre via comando:

pg_ctl start -l /home/postgres/saida.txt

O sucesso do comando acima pode ser verificado investigando o arquivo de logs, neste caso, /home/postgres/saida.txt, bem como checando se os três processos básicos estão na memória, cada um identificado por um process identifier (pid). Suas descrições podem ser visualizadas graças ao comando ps –C postmaster:

• postmaster • postgres : stat buffer process • postgres: stats collector

O primeiro processo, postmaster, desempenha o papel mais importante pois a partir dele outros processos, chamados postgres, serão disparados. Inclusive, cada conexão criada também ocasionará um novo processo postgres.

Page 10: Entendendo-PostgreSQL

Outra forma alternativa seria:

postmaster -i

Obs: O argumento -i é para que o banco aceite conexões tcp/ip, caso o argumento “S” fosse acrescentado depois do “i” a execução do banco seria em modo silencioso, ou seja, o log não mostraria no console corrente.

3.7 – Criação de um Banco Regular

A criação de um banco de dados concretiza-se graças ao comando createdb. Na verdade, trata-se de um script semelhante a initdb e pg_ctl. Eles residem no diretório: pgsql/bin. Exemplo:

createdb teste

3.8 – Conexão

Finalmente, para que conexões possam acontecer a um banco de dados, deve-se utilizar o comando psql:

psql –d teste

onde o parâmetro –d indica o banco ao qual deseja conectar-se.

3.9 – Indisponibilização

Uma vez encerradas as conexões, pode-se retirar o PostgreSQL da memória via:

pg_ctl stop -m s

Page 11: Entendendo-PostgreSQL

6. FAQ

4.1. Antes de tudo é necessário verificar se o compilador da linguagem C (GCC) já está instalado.

Abra o console e digite:

sudo apt-get install gcc,build-essential

Caso já esteja instalado ele vai indicar que já está instalado, caso contrário o gerenciador de pacotes padrão vai instalar tudo automaticamente para você. Caso o seu sistema não seja o ubuntu (debian), o gerenciador de pacotes provavelmente não vai ser o apt-get, vai ser outro por exemplo: yum , yast.

No Ubuntu, esse passo de instalação do gcc pode ser feito também através da interface gráfica, basta entrar em Sistema > Administração > Gerenciador de Pacotes Synaptic. Então basta pesquisar pelos pacotes gcc e build-essential, caso eles estejam instalados já vai aparecer marcado o checkbox caso contrário marque os checkboxs e clique no botão aplicar para que o compilador seja instalado automaticamente.

4.2. Obtendo o pgadmin

O pgadmin pode ser obtido da mesma maneira que foi obtido o gcc, através de um gerenciador de pacotes através do comando:

sudo apt-get install pgadmin3

Caso este pacote não esteja na sua lista de pacotes vá até o site oficial do postgres e na seção download baixe o instalador e instale.

Page 12: Entendendo-PostgreSQL

4.3. Ambiente de desenvolvimento

Para que o desenvolvimento dentro do código fonte do projeto PostgreSQL se torne produtivo, é fundamental que uma “IDE” seja utilizada para otimizar tarefas como edição de código,compilação, instalação. Grande parte dos desenvolvedores da linguagem utilizam uma ide chamada eclipse, mas eu particularmente prefiro usar o netbeans. Para baixar o netbeans para desenvolvimento em C entre na sua página oficial http://www.netbeans.org/ e na seção de download baixe o netbeans voltado para c/c++.

4.4. Parar o processo que está rodando em background: kill `cat /usr/local/pgsql/data/postmaster.pid` ps -a kill -9 pid

4.5. Troca de usuário para root: su – root

4.6. Troca de usuário para o postgres: su – postgres

4.7. Criar os diretórios onde os dados serão armazenados:

Page 13: Entendendo-PostgreSQL

mkdir /usr/local/pgsql/data chown postgres /usr/local/pgsql/data

Page 14: Entendendo-PostgreSQL

7. Utilizando o GDB

O primeiro passo consiste em configurar o postgres com a opção --enable-debug. No meu caso, executo o seguinte comando no diretório do postgres:

./configure --prefix=diretorio_de_instalacao --enable-debug --enable-cassert --enable-depend

Após a compilação (gmake), instalação (gmake install) e ajuste das variáveis de ambiente (PATH, PGDATA, LD_LIBRARY_PATH, etc), conforme a documentação, já é possível executar o postgres. A maneira mais fácil de utilizá-lo com o gdb é criando um banco de dados com o nome do usuario do linux (createdb nome_usuario) e executando os comandos "gdb postmaster" ou "gdb postgres".

Deste modo, o postgres será executado com o gdb no modo de "interactive backend", onde apenas um processo servidor/cliente é criado, e o cliente é logado automaticamente no banco de dados com o nome do usuário. É possível debugar também executando o postgres no modo normal, com a criação de um processo "postmaster" e processos servidores para cada cliente, mas o mecanismo é bem mais complicado e no nosso caso não será necessário.

Comandos importantes do gdb:

"b nome_funcao" - criacao de breakpoints

"run" - inicio da execucao do postgres, o qual so sera interrompido quando passar por um breakpoint ou quando o usuario digitar "CTRL+C"

"next" - executa a proxima instrucao

"step" - entra na funcao

"print variavel" - mostra o valor de uma variavel

"bt" - mostra um trace do programa, com as funcoes chamadas

"cont" - continua a execucao do postgres apos a interrupcao

"kill" - finaliza a execucao

"help" - ajuda do gdb

Outra dica: sempre que o "enter" for apertado o comando anterior será executado novamente no gdb.

8. Referências Bibliográficas

http://www.postgres.org

http://developers.sun.com/tools/cc/articles/mixing.html

Page 15: Entendendo-PostgreSQL

Alterando a Política de Substituição de Páginas de Memória do PostgreSQL

1. O Gerenciador de Memória

O desempenho de consultas em sistemas gerenciadores de bancos de dados é um dos indicadores mais importantes de sua qualidade, e a maior parte da pesquisa em bancos de dados está direcionada para este objetivo. Um dos fatores críticos para o desempenho de consultas é o bom gerenciamento da informação em memória, já que o que geralmente determina o tempo de execução de uma consulta é a quantidade de operações de entrada e saída (E/S), do disco para a memória. Os sistemas operacionais possuem um gerenciador de memória (“buffer manager”), o qual poderia teoricamente ser usado para controlar as páginas dos SGBDs em memória, porém este mecanismo seria muito ineficiente, devido às particularidades de acessos à informação em SGBDs. Logo, é necessária a existência de um gerenciador de memória exclusivo em um SGBD para acelerar as consultas feitas por este. Além disto, o gerenciador de memória possibilita a implementação de políticas de recuperação, como a “Write Ahead Logging”, e um melhor controle de bloqueios.

O gerenciador de memória é o componente do SGBD responsável pelo gerenciamento de um espaço limitado de memória para armazenar páginas de dados reduzindo o número de operações de leitura a disco por transação. Funciona como uma interface entre a memória principal e o disco.

O papel principal do gerenciador de memória consiste em responder a pedidos de acesso em memória de páginas do disco. Quando a memória é completamente preenchida, uma página deve ser removida para que outra seja alocada. Se a página em memória tiver sido modificada, esta deve ser armazenada em disco antes de ser removida. A escolha de qual página deve ser removida da memória é de grande importância, pois há grande chance de que uma página removida tenha que ser utilizada novamente e retornar à memória no futuro. O gerenciador de memória tenta então prever quais páginas em memória não deverão ser utilizadas novamente no futuro próximo para selecionar as que deverão ser removidas da memória. Para isso, diferentes políticas de substituição de páginas podem ser adotadas.

Neste trabalho apresentamos algumas políticas de substituição de páginas da memória (“buffer”) mais populares, e suas vantagens e desvantagens. Em seguida descrevemos a implementação existente da política de LRU (“Least Recently Used”) no PostgreSQL e a implementação feita da política de MRU (“Most Recently Used”). Finalmente, apresentaremos os resultados dos testes realizados para comparar o desempenho das duas políticas e as conclusões obtidas.

Page 16: Entendendo-PostgreSQL

2. Políticas de Substituição de Páginas As políticas de substituição de páginas utilizadas para gerenciar uma área de memória podem ser classificadas de acordo com as considerações seguidas por uma política:

- Idade da página: contada desde a primeira referência ou desde a última; - Contabilizar todas as referências; - Contabilizar somente a referência mais recente.

A política FIFO, por exemplo, substitui a página mais antiga sem levar em consideração a freqüência de acesso nem a idade da página, contada desde a primeira referencia é o único critério de decisão. Esta política tem bons resultados para acesso seqüencial.

Um dos algoritmos mais utilizados, o LRU, substitui as páginas do buffer que foram utilizadas menos recentemente. A decisão de substituição é determinada pela “idade” de cada página do buffer desde a sua mais recente referência. Esta política leva em consideração o “Princípio da localidade Temporal”, já que as páginas acessadas recentemente costumam ter maior chance de serem acessadas novamente e, neste caso, não são retiradas da memória.

A política LRU é usada para gerenciar o buffer do PostgreSQL, que apresenta vantagens como melhor aproveitamento das páginas mais usadas em memória, mas em contra partida apresenta um algoritmo muito mais complexo em relação às outras políticas de gerenciamento de buffer.

Já a política MRU substitui as páginas do buffer que foram utilizadas mais recentemente. Escolhemos implementar a política MRU no PostgreSQL por questão de simplicidade.

3. Implementação Para podermos implementar uma política alternativa de gerência de buffer, foi necessário uma análise no código fonte do PostgreSQL. Foi observado que o PostgreSQL implementa a política LRU de gerência de Buffer.

O PostgreSQL utiliza uma estrutura em lista chamada de “BufferDesc” para organizar o Buffer em memória e uma serie de funções para manipulá-la. Essa estrutura possui uma série de atributos que auxiliam no gerenciamento do Buffer, como é o exemplo do atributo “refcount” que informa se a página que está sendo referenciada por esse “nó” da estrutura está “pinned”, ou seja, se a página esta bloqueada ou não e quantos bloqueios ela possui.

Além dos atributos essa estrutura possui dois ponteiros (freeNext e freePrev) para uma outra estruturas de dados. Esses dois ponteiros apontam para uma lista encadeada que possui os endereços das próximas páginas candidatas a serem retiradas da memória. Essa “lista auxiliar” é essencial para implementar o LRU, pois cada vez que uma página é acessada ela é inserida no final desta lista. Logo, a página mais recentemente utilizada está no final da lista e menos recentemente utilizada está no início da lista.

Page 17: Entendendo-PostgreSQL

Estrutura do BufferDesc: typedef struct sbufdesc { Buffer freeNext; /* links for freelist chain */ Buffer freePrev; SHMEM_OFFSET data; /* pointer to data in buf pool */ /* tag and id must be together for table lookup (still true?) */ BufferTag tag; /* file/block identifier */ In buf_id; /* buffer's index number (from 0) */ BufFlags flags; /* see bit definitions above */ unsigned refcount; /* # of backends holding pins on buffer */ LWLockId io_in_progress_lock; /* to wait for I/O to complete */ LWLockId cntx_lock; /* to lock access to page context */ Bool cntxDirty; /* new way to mark block as dirty */ /* * We can't physically remove items from a disk page if another * backend has the buffer pinned. Hence, a backend may need to wait * for all other pins to go away. This is signaled by setting its own * backend ID into wait_backend_id and setting flag bit * BM_PIN_COUNT_WAITER. At present, there can be only one such waiter * per buffer. */ BackendId wait_backend_id; /* backend ID of pin-count waiter */ } BufferDesc;

Para que pudéssemos colocar em prática a política Gerência de Buffer MRU foi preciso modificar apenas uma linha de código. No momento de retirar uma página, ao invés de escolher a página que está no início da lista (menos recentemente utilizada) escolhemos a página que está no final da lista (mais recentemente utilizada).

Para a visualização durante a execução de testes, cada vez que uma página é acessada, escrita, removida ou inserida na memória, é impresso na tela o número do buffer em questão, o seu contador de referências e o identificador da relação que possui a página. A versão original da implementação da política de LRU também foi modificada para imprimir em tela o número do buffer e o identificador da relação nas mesmas situações, facilitando a comparação entre as duas políticas.

… if (freeBuf == NULL) { elog(LOG, "Nao foi encontrado buffer livre!!!"); } else { elog(LOG, "Buffer %d livre, contador %d, relacao antiga %d", freeBuf->buf_id, freeBuf->counter, freeBuf->tag.rnode.relNode);

A modificação mais importante feita no código foi na função GetFreeBuffer, que está no arquivo src/backend/storage/buffer/freelist.c, onde é removida a pagina menos referenciada da memória. Esta função é mostrada a seguir:

Page 18: Entendendo-PostgreSQL

* GetFreeBuffer() -- get the 'next' buffer from the freelist.

*/

BufferDesc *

GetFreeBuffer(void)

{

BufferDesc *buf;

if (Free_List_Descriptor == SharedFreeList->freeNext)

{

/* queue is empty. All buffers in the buffer pool are pinned. */

ereport(ERROR,

(errcode(ERRCODE_INSUFFICIENT_RESOURCES),

errmsg("out of free buffers")));

return NULL;

}

buf = &(BufferDescriptors[SharedFreeList->freeNext]);

/* remove from freelist queue */

BufferDescriptors[buf->freeNext].freePrev = buf->freePrev;

BufferDescriptors[buf->freePrev].freeNext = buf->freeNext;

buf->freeNext = buf->freePrev = INVALID_DESCRIPTOR;

buf->flags &= ~(BM_FREE);

return buf;

}

Page 19: Entendendo-PostgreSQL

Observe que:

buf = &(BufferDescriptors[SharedFreeList->freeNext]);

Atribui à variável buf a página que está no início da lista (ou seja, a página utilizada menos recentemente).

Como a lista é duplamente encadeada

buf->freePrev

Representa a página que está no final da lista (ou seja, a página utilizada mais recentemente).

Logo, para implementar o MRU e exclui a página mais recentemente utilizada (final da lista) basta fazer:

Buf = buf->freePrev

Assim, apontamos para a página que está no final da lista (mais recentemente utilizada).

Page 20: Entendendo-PostgreSQL

O código alterado ficará então da seguinte forma:

* GetFreeBuffer() -- get the 'next' buffer from the freelist.

*/

BufferDesc *

GetFreeBuffer(void)

{

BufferDesc *buf;

if (Free_List_Descriptor == SharedFreeList->freeNext)

{

/* queue is empty. All buffers in the buffer pool are

pinned. */

ereport(ERROR,

(errcode(ERRCODE_INSUFFICIENT_RESOURCES),

errmsg("out of free buffers")));

return NULL;

}

buf = &(BufferDescriptors[SharedFreeList->freeNext]);

Buf = buf->freePrev /* remove from freelist queue */

BufferDescriptors[buf->freeNext].freePrev = buf->freePrev;

BufferDescriptors[buf->freePrev].freeNext = buf->freeNext;

buf->freeNext = buf->freePrev = INVALID_DESCRIPTOR;

buf->flags &= ~(BM_FREE);

return buf;

}

Page 21: Entendendo-PostgreSQL

4. Referências [1] Principles of Database Buffer Management

Wolfgang Effelsberg IBM Scientific Center, Heidelberg THEO HAERDE University of Kaiserslautern

[2] PostgreSQL - Manual de referência www.postgresql.org