You are on page 1of 17

UNIVERSIDADE TECNOLÓGICA FEDERAL DO PARANÁ

DEPARTAMENTO ACADÊMICO DE INFORMÁTICA


CURSO DE SISTEMAS DA INFORMAÇÃO

EMERSON SHIGUEO SUGIMOTO


VAGNER VENGUE

Projeto de Banco de Dados 2

CURITIBA
2010
UNIVERSIDADE TECNOLÓGICA FEDERAL DO PARANÁ
DEPARTAMENTO ACADÊMICO DE INFORMÁTICA
CURSO DE SISTEMAS DA INFORMAÇÃO

EMERSON SHIGUEO SUGIMOTO


VAGNER VENGUE

Projeto de Banco de Dados 2

Trabalho acadêmico apresentado à


disciplina de Banco de Dados 2.

Universidade Tecnológica Federal


do Paraná. Unidade de Curitiba.

Professor Dr.: André Luís Vignatti.

CURITIBA
2010
SUMÁRIO

ÍNDICE DE FIGURAS ........................................................................................ 4


1. INTRODUÇÃO ............................................................................................. 5

1.1 TEMA .................................................................................................... 5


1.2 OBJETIVOS GERAIS E ESPECÍFICOS ............................................... 6

1.2.1 Gerais ............................................................................................. 6


1.2.2 Específicos ..................................................................................... 6
1.3 PROCEDIMENTOS METODOLÓGICOS.............................................. 6

2. IMPLEMENTAÇÃO ...................................................................................... 7

1.4 ESTRUTURA DE DADOS ..................................................................... 7


1.5 PRINCIPAIS FUNÇÕES ..................................................................... 13
1.6 FORMATO DE ENTRADA E SAÍDA DE DADOS ............................... 15

2. CONCLUSÃO ............................................................................................ 16
3. REFERÊNCIAS BIBLIOGRAFIAS ............................................................. 17
ÍNDICE DE FIGURAS

Figura 1 - Classe No. ......................................................................................... 7


Figura 2 - Classe Grafo.cpp............................................................................. 13
Figura 3 - Entrada programa ........................................................................... 13
Figura 4 - Exemplo de Saída de Execução ..................................................... 14
Figura 5 - Pasta e Arquivos Gerados .............................................................. 14
Figura 6 - Exemplo de grafo ............................................................................ 14
1. INTRODUÇÃO

A serialização de transações é uma operação muito importante em


qualquer Sistema Gerenciador de Banco de Dados (SGBD). É através da
serialização que o SGBD consegue intercalar de forma que as operações de
leitura e escrita de uma transação não interfiram nas operações de outra
transação.
A execução concorrente de transações (na execução concorrente, duas
ou mais transações executam operações concomitantemente) em um banco de
dados permite que transações diferentes executem concomitantemente sem
que uma transação interfira na execução da outra, garantindo o ACID (ACID é
um acrônimo de Atomicidade, Consistência, Isolamento e Durabilidade). O
controle de concorrência evita que diversos erros possam ocorrer, como a
duplicação de dados em uma base devido a um erro de execução, dados
inconsistentes que podem ser gerados devido à execução concomitante.
(exemplo clássico da transação de uma conta corrente para outra, etc.).
O presente trabalho tem por objetivo desenvolver um programa que
decide se um plano de execução concorrente é ou não serializável, e caso seja
serializável, exibir um possível plano de execução e caso contrário exibir o ciclo
do grafo. E a criação dos grafos através do software GraphViz.
O programa foi desenvolvido com a linguagem C++, utilizando o ambiente
de desenvolvimento Visual Studio C++ versão 2008, e posteriormente foi
recriado no software Dev-C++, versão 4.9.8.0. Devido ao compilador utilizado,
o seu funcionamento é suportado pelos atuais sistemas operacionais da família
Microsoft Windows, porém se compilado em um compilador Linux, como o
gcc++ versão 4.4.2, o mesmo funcionará em plataforma Linux.

1.1 TEMA

Construção de um grafo à partir das entradas do usuário de um plano de


execução concorrente, uso de algoritmo de identificação de ciclos em um grafo
e exibição do grafo através do software GraphViz.
1.2 OBJETIVOS GERAIS E ESPECÍFICOS

1.2.1 Gerais

Identificação de ciclos em um grafo.

1.2.2 Específicos

Desenvolver um programa que decide se um plano de execução


concorrente é ou não serializável, e caso seja serializável, exibir um possível
plano de execução e caso contrário exibir o ciclo do grafo. E a criação dos
grafos através do software GraphViz.

1.3 PROCEDIMENTOS METODOLÓGICOS

Para o desenvolvimento do programa foi feita primeiramente uma análise


do problema e então desenvolvido um conjunto de classes para a manipulação
dos arquivos de entradas e a criação dos grafos dos planos de execução.
Depois foram desenvolvidas funções para análise dos ciclos nos grafos e
exibição dos possíveis planos de execução e em caso de ciclo, da exibição do
ciclo. Por fim realizamos uma pesquisa sobre o software GraphViz e a
comunicação no nosso software com o GraphViz.
2. IMPLEMENTAÇÃO

A implementação do programa, objeto deste trabalho, inclui estruturas


que representam os grafos dos planos de execução concorrentes, entre eles,
as classes Grafo.cpp e No.cpp.

1.4 ESTRUTURA DE DADOS

A classe No.cpp (Figura 1) tem por objetivo representar no nodo de um


grafo. A classe Grafp.cpp (Figura 2) analisa o grafo e verifica os possíveis
ciclos.

#include "No.h"

No::No(const int val)


{
setValor( val );
}

int No::setValor(const int v)


{
_valor = v;
}

int No::getValor() const


{
return _valor;
}

void No::addLigacao(No* const lig)


{
if ( !existeLigacao( lig ) )
_ligacoes.push_back( lig );
}

bool No::existeLigacao(No* const lig)


{
bool existe = false;
for (list<No*>::iterator it = _ligacoes.begin(); it != _ligacoes.end(); it++)
{
if ((*it) == lig)
{
existe = true;
break;
}
}
return existe;
}

list<No*> No::getLigacoes() const


{
return _ligacoes;
}
Figura 1 - Classe No.
#include "Grafo.h"

Grafo::Grafo()
{ }

void Grafo::addNo(No* const novo)


{
if (! existeNo( novo ) )
{
_nos.push_back( novo );
}
}

list<No*> Grafo::getNos() const


{
return _nos;
}

bool Grafo::existeNo(No* const no)


{
bool existe = false;
for (list<No*>::iterator it = _nos.begin(); it != _nos.end(); it++)
{
if ( (*it) == no )
{
existe = true;
}
}
return existe;
}

bool Grafo::existeCiclo()
{
// verifica cada um dos nós, evitando que ciclos em grafos disconexos sejam
perdidos;
// este laço (mais externo) deverá executar poucas vezes, a menos que o grafo
esteja totalmente disconexo, no pior caso;

list<No*> visitados;
bool noVisitado;
bool existe = false;
for (list<No*>::iterator itNo = _nos.begin(); itNo != _nos.end(); itNo++)
{
noVisitado = false;
for (list<No*>::iterator itVst = visitados.begin(); itVst !=
visitados.end(); itVst++)
{
if ((*itNo) == (*itVst))
{
noVisitado = true;
}
}

if ( !noVisitado )
{
existe = existeCiclo((*itNo), &visitados);
if ( existe )
break;
}
}
return existe;
}

list< list<No*> > Grafo::getCiclos()


{
list< list<No*> > lstCiclos;
list<No*> visitados;
list<No*>* caminho; // caminho vazio;
bool visitado;

for (list<No*>::iterator itNo = _nos.begin(); itNo != _nos.end(); itNo++)


{
visitado = false;
for (list<No*>::iterator itVst = visitados.begin(); itVst !=
visitados.end(); itVst++)
{
if ((*itVst) == (*itNo))
visitado = true;
}

if ( !visitado )
{
caminho = new list<No*>;
getCiclos((*itNo), &lstCiclos, *caminho, &visitados);
delete caminho;
}
}
return lstCiclos;
}

list< list<No*> > Grafo::getCaminhosSemCiclos()


{
list< list<No*> > lstCaminhos;

if ( existeCiclo() )
return lstCaminhos; // se houver cíclos, retorna a lista vazia;

list<No*> visitados;
list<No*>* caminho; // caminho vazio;
bool visitado;

for (list<No*>::iterator itNo = _nos.begin(); itNo!= _nos.end(); itNo++)


{
visitado = false;
for (list<No*>::iterator itVst = visitados.begin(); itVst !=
visitados.end(); itVst++)
{
if ((*itVst) == (*itNo))
visitado = true;
}

if ( !visitado )
{
caminho = new list<No*>;
getCaminhosSemCiclos((*itNo), &lstCaminhos, *caminho);
delete caminho;
}
}

return lstCaminhos;
}

/**
** Método recursivo que realiza uma busca por caminhos sem cíclos do grafo, segundo a
direção das arestas.
*/
void Grafo::getCaminhosSemCiclos(No* no, list< list<No*> >* lstCaminhos, list<No*>
caminho)
{
if (NULL == no || NULL == lstCaminhos)
return;

caminho.push_back( no );

list<No*> ligas = no->getLigacoes();


if ( ligas.size() == 0 )
{
lstCaminhos->push_back( caminho );
}
else
{
for (list<No*>::iterator it = ligas.begin(); it != ligas.end(); it++)
{
getCaminhosSemCiclos((*it), lstCaminhos, caminho);
}
}
}

//--------------------------------------------------------------------------------------

/**
** Método recursivo que realiza uma busca por todos os cíclos diferentes do grafo.
*/
void Grafo::getCiclos(No* no, list< list<No*> >* lstCiclos, list<No*> caminho,
list<No*>* visitados)
{
// verifica se os parâmetros não são nulos;

// verifica se este nó já foi visitado:


// se não:
// adiciona a lista de nós visitados;

// verifica se este nó forma um cíclo com algum dos nós da lista de nós
'caminho':
// se sim:
// cria uma lista de nós para representar o cíclo entre este nó e
o nó que forma o cíclo;
// verifica se este cíclo ainda não está na lista de cíclos
'lstCiclos':
// se não:
// adiciona o cíclo a lista;

// se não:
// adiciona o nó a lista de nós que representa o caminho até aqui;
// faz uma chama recursiva a este método para cada um dos nós
'apontados' por este nó;

// retorna o valor da lista de cíclos 'lstCiclos';


if ( NULL == no || NULL == lstCiclos || NULL == visitados )
return;

bool visitado = false;


for (list<No*>::iterator it = visitados->begin(); it != visitados->end(); it++)
if ((*it) == no)
visitado = true;

if ( !visitado )
visitados->push_back( no );

bool forma_ciclo = false;


list<No*> novo_ciclo;
for (list<No*>::iterator it = caminho.begin(); it != caminho.end(); it++)
{
if ( (*it) == no )
forma_ciclo = true;

if ( forma_ciclo )
novo_ciclo.push_back( *it );
}

bool ciclo_repetido = false;


if ( forma_ciclo )
{
for (list< list<No*> >::iterator it = lstCiclos->begin(); it !=
lstCiclos->end(); it++)
{
if ( ciclosIguais(&novo_ciclo, &(*it)) )
ciclo_repetido = true;
}

if ( !ciclo_repetido )
{
//novo_ciclo.push_back( no );
lstCiclos->push_back( novo_ciclo );
}
}
else
{
caminho.push_back( no );
list<No*> ligas = no->getLigacoes();
for (list<No*>::iterator it = ligas.begin(); it != ligas.end(); it++)
{
getCiclos((*it), lstCiclos, caminho, visitados);
}
}
}

/**
** Verifica se dois cíclos do grafo são iguais.
**
** parâmetro cF: ponteiro para uma lista de nós que deve representar um dos cíclos.
** parâmetro cS: ponteiro para uma lista de nós que deve representar o cíclo a ser
comparado.
** retorna: true se os cíclos forem iguais, ou false, caso contrário.
*/
bool Grafo::ciclosIguais(list<No*>* cF, list<No*>* cS)
{
// se as listas são de tamanhos diferentes;
if ( cF->size() != cS->size() )
return false;

list<No*>::iterator itF, itS;


itF = cF->begin();
itS = cS->begin();

// procura por um nó que esteja presente nas duas listas;


while ( itS != cS->end() && (*itF) != (*itS) )
{
itS ++;
}

// se não foi encontrado nós iguais nas listas;


if ((*itF) != (*itS))
return false;

// compara todos os i-ésimos nós das listas;


int tamanho = cF->size();
for (int i = 0; i < tamanho; i++)
{
itF ++;
itS ++;

if (itF == cF->end())
itF = cF->begin();

if (itS == cS->end())
itS = cS->begin();

if ((*itF) != (*itS))
{
return false;
}
}

return true;
}

//--------------------------------------------------------------------------------------
-------

/**
** Método recursivo que verifica se existe pelo menos um cíclo no grafo.
**
** parâmetro no: ponteiro para o nó raiz para a verificação.
** parâmetro visitados: ponteiro para uma lista com os ponteiros dos nós já visitados.
** retorna: true se existe pelo menos um cíclo, ou false, caso contrário.
*/
bool Grafo::existeCiclo(No* no, list<No*>* visitados)
{
// recupera ligações do nó;

// para cada ligação:


// verifica se o nó já foi visitado;
// se sim:
// verfica se existe um caminho deste nó visitado até o nó
recebido no parâmetro, dentre os nós já visitados;
// se sim: retorna true;

// se não:
// marca o nó como visitado;

// para cada ligação:


// faz uma chamada recursiva do método;
// se o método retornar true:
// guarda o resultado E para o laço;
// se não:
// guarda o resultado;
// retorna o resultado;

list<No*> ligas = no->getLigacoes();


bool noVisitado = false;
for (list<No*>::iterator itLiga = ligas.begin(); itLiga != ligas.end(); itLiga++)
{
for (list<No*>::iterator itVst = visitados->begin(); itVst != visitados-
>end(); itVst++)
{
if ( (*itVst) == (*itLiga) )
{
noVisitado = true;
}
}

if ( noVisitado )
{
list<No*> lstVazia;
if ( existeCaminho(&lstVazia, (*itLiga), no) )
{
return true;
}
}
else
{
visitados->push_back((*itLiga));
}
}

bool rt = false;
for (list<No*>::iterator itLiga = ligas.begin(); itLiga != ligas.end(); itLiga++)
{
rt = existeCiclo((*itLiga), visitados);
if ( rt )
break;
}

return rt;
}

/**
** Método recursivo que verifica se existe um caminho entre um nó e outro entre uma
lista de nós.
**
** parâmetro lstNos: um ponteiro para uma lista de nós, onde o caminho deve ser
procurado.
** parâmetro ini: ponteiro para o nó de início do caminho.
** parâmetro fim: ponteiro para o nó de fim do caminho.
** retorna: true se existir um caminho, ou false, caso não exista.
*/
bool Grafo::existeCaminho(list<No*>* lstNos, No* ini, No* fim)
{
// verifica se o nó de ini é igual ao de fim;
// se sim:
// retorna true, pois existe um caminho;
// se não:
// marca o nó de início como visitado;

// recupera a lista de ligações do nó de início;


// para cada ligação:
// faz uma chamada recursiva ao método;
// se o resultado for true:
// guarda o resultado E para o laço;
// se não:
// guarda o resultado;

// retorna o resultado;

if (ini == fim)
{
return true;
}
else
{
lstNos->push_back( ini );
}
list<No*> ligas = ini->getLigacoes();
bool rt = false;
for (list<No*>::iterator it = ligas.begin(); it != ligas.end(); it++)
{
rt = existeCaminho(lstNos, (*it), fim);
if ( rt )
break;
}
return rt;
}
Figura 2 - Classe Grafo.cpp

1.5 PRINCIPAIS FUNÇÕES

O programa inicialmente espera a entrada do nome do arquivo do


notepad (.txt) com os planos de execução concorrentes (Figura 3).

Figura 3 - Entrada programa

Como exemplo de planos de execução, o referido arquivo teste.txt de


entrada da Figura 3 contém os seguintes planos:

r1(X),r3(X),w1(X),r2(X),w3(X)

r1(X),r3(X),w3(X),w1(X),r2(X)

r3(X),r2(X),r1(X),w3(X),w1(X)

r1(X),r2(Z),r1(Z),r3(X),r3(Y),w1(X),w3(Y),r2(Y),w2(Z),w2(Y)

r1(X),r2(Z),r3(X),r1(Z),r2(Y),r3(Y),w1(X),w2(Z),w3(Y),w2(Y)

r2(Z),r2(Y),w2(Y),r3(Y),r3(Z),r1(X),w1(X),w3(Y),w3(Z),r2(X),r1(Y),w1(Y),w2(X).

r3(Y),r3(Z),r1(X),w1(X),w3(Y),w3(Z),r2(Z),r1(Y),w1(Y),r2(Y),w2(Y),r2(X),w2(X).

r123(X),r311(X),w123(X),r312(X),w311(X)

r12(X),r3(X),w12(X),r2(X),w3(X).

Na Figura 4 esta um exemplo de saída da entrada de teste.txt (Figura 3).


Nesta saída são exibidos os planos de execução, e caso possuam ciclos ele
retorna os ciclos existentes, caos contrário ele exibe um possível plano de
execução. Posteriormente à execução, o programa automaticamente cria na
pasta imagem (Figura 5) os arquivos de extensão ‘.gv’ referentes ao software
GraphViz e as respectivas imagens dos grafos.
Figura 4 - Exemplo de Saída de Execução

Figura 5 - Pasta e Arquivos Gerados

Na Figura 6 esta representado um grafo gerado pelo GraphViz à partir do


plano de execução:
r1(X),r3(X),w1(X),r2(X),w3(X)

Figura 6 - Exemplo de grafo


1.6 FORMATO DE ENTRADA E SAÍDA DE DADOS

O programa recebe como entrada um arquivo de extensão ‘.txt’ com os


respectivos planos de execução concorrentes, como por exemplo:

r1(X),r3(X),w1(X),r2(X),w3(X)

r1(X),r3(X),w3(X),w1(X),r2(X)

r3(X),r2(X),r1(X),w3(X),w1(X)

r1(X),r2(Z),r1(Z),r3(X),r3(Y),w1(X),w3(Y),r2(Y),w2(Z),w2(Y)

r1(X),r2(Z),r3(X),r1(Z),r2(Y),r3(Y),w1(X),w2(Z),w3(Y),w2(Y)

r2(Z),r2(Y),w2(Y),r3(Y),r3(Z),r1(X),w1(X),w3(Y),w3(Z),r2(X),r1(Y),w1(Y),w2(X).

r3(Y),r3(Z),r1(X),w1(X),w3(Y),w3(Z),r2(Z),r1(Y),w1(Y),r2(Y),w2(Y),r2(X),w2(X).

r123(X),r311(X),w123(X),r312(X),w311(X)

r12(X),r3(X),w12(X),r2(X),w3(X).

Os planos devem estar separados entre si por uma quebra de linha


(enter) e as operações de cada transação devem estar separadas entre si por
uma vírgula. Ao final de um plano de execução pode-se opcionalmente
adicionar um ponto (.) para indicar o fim do plano de execução.
Entende-se que uma operação de leitura (read) é representada por um r,
e uma operação de escrita (write), representada por w. Desta forma r1(X) e
w1(X), representam respectivamente uma leitura e uma escrita no item X.
Cada transação é representada por um número, por exemplo, r3
representa uma operação de leitura da transação de número 3 e w14
representa uma operação de escrita da transação de número 14.
As leituras e escritas são dependentes das transações e dos itens que
estão lendo/escrevendo, assim sendo r1(X) é diferente de r1(Y), e w1(X) é
diferente de w2(X), e vice-versa.
2. CONCLUSÃO

O trabalho nos permitiu ter uma visão mais ampla de como um SGBD
consegue serializar um plano de execução de forma a intercalar as transações
sem que estas conflitem entre si.
Através do desenvolvimento do software colocamos em prática os
conceitos vistos em sala de aula e também das disciplinas já vistas, como a
disciplina de Estruturas de Dados 1, a qual nos forneceu uma base para poder
criar uma estrutura que represente o grafo de uma plano de execução
concorrente.
3. REFERÊNCIAS BIBLIOGRAFIAS

1. Dev-C++. Ferramenta para desenvolvimento de softwares. Disponível


em: <http://sourceforge.net/projects/dev-cpp/files/Binaries/>. Acesso em:
18.abril.2010.

2. Visual Studio C++. Ferramenta para desenvolvimento de software.


Disponível em: <http://www.microsoft.com/express/Windows/>. Acesso
em: 14.março.2010.

3. Graphviz. Gerador de gráficos hierárquicos. Disponível em:


<http://graphviz.org>. Acesso em: 18.agosto.2010.

4. Wikipédia. Linguagem utilizada no software Graphviz. Disponível em:


<http://en.wikipedia.org/wiki/DOT_language>. Aceso em:
18.agosto.2010.

5. Loria. API em Java para acesso ao GraphViz. Disponível em:


<http://www.loria.fr/~szathmar/off/projects/java/GraphVizAPI/index.php>.
Acesso em: 18.agosto.2010.