Skip to content

Commit 3f2a15b

Browse files
committed
upload original files
0 parents  commit 3f2a15b

24 files changed

+3131
-0
lines changed

README.md

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
2+
# Projeto de Sistemas Distribuídos 2020/2021
3+
4+
Concretização de um serviço de armazenação de pares chave-valor. Iremos utilizar uma árvore binária de pesquisa para armazenar informação, dada a sua elevada eficiência ao nível da pesquisa. Sendo este tipo de serviço utilizado em sistemas distribuídos torna-se imperativa a troca de informação via rede. Neste sentido foram desenvolvidos mecanismos de serialização/deserialização a utilizar no envio/receção de informação, utilizando o **protocol buffer**. Desta forma, pretende-se a concretização da árvore binária de pesquisa num servidor, e à implementação de um cliente com uma interface de gestão do conteúdo da árvore binária. Isto implica que:
5+
6+
1. Através do cliente, o utilizador irá invocar operações, que serão transformadas em mensagens e enviadas pela rede até ao servidor.
7+
8+
2. Este, por sua vez interpretará essas mensagens, e:
9+
a. Realizará as operações correspondentes na árvore local concretizada por ele.
10+
b. Enviará posteriormente a resposta transformada em mensagem, ao cliente
11+
12+
3. Por sua vez, o cliente interpretará a mensagem de resposta
13+
4. O Cliente procederá de acordo com o resultado, ficando de seguida pronto para a próxima operação.
14+
15+
O objetivo será fornecer às aplicações que usariam esta árvore um modelo de comunicação tipo **RPC**, onde vários clientes acedem a uma mesma árvore binária de pesquisa partilhada. Para tal, criámos um sistema concorrente que aceita pedidos de múltiplos clientes em simultâneo através do uso de multiplexagem de I/O e que separa o tratamento de I/O do processamento de dados através do uso de *Threads*.
16+
17+
Mais concretamente temos, para além da multiplexagem de I/O, foram implementadas:
18+
19+
- Respostas assíncronas aos pedidos de escrita dos clientes, ou seja, em vez de executar imediatamente pedidos de escrita, o servidor devolve aos clientes um identificador da operação e passa a guardar os pedidos numa fila temporária para serem executados por uma thread
20+
- Garantia de sincronização e threads no acesso à árvore e à Fila de Tarefas através do uso de Locks e Variáveis Condicionais.
21+
22+
No âmbito de suporte a tolerância a falhas, desenvolvemos um sistema de replicação com base no modelo de replicação passiva com primário fixo, através do serviço de coordenação **ZooKeeper**.
23+
24+
Uma descrição mais detalhada do projeto em conjunto com a sua especificação encontra-se dividida pelos quatro enunciados.
25+
26+
---
27+
28+
## Estrutura
29+
30+
`/include/`- contém os header *.h* requiridos pelo C
31+
`/source/` - contém o código fonte do projeto
32+
`/object/` - diretório que irá conter *object files*
33+
`/binary/` - executáveis resultantes do *linking* de *object files*
34+
`/lib/` - bibliotecas criadas na compilação
35+
36+
Encontram-se também, na root do projeto:
37+
38+
- README.md
39+
- makefile: define as regras de compilação e ligação
40+
- sdmessage.proto: esquema do *Protocol Buffer*
41+
42+
---
43+
44+
## Compilação e Execução
45+
46+
Em baixo encontram-se comandos principais e alguns exemplos de utilização
47+
48+
- **Compilação e ligação:** `make`
49+
50+
- **Execução de um servidor:** `./binary/tree-server <porto_servidor> <IP:Porto Zookeeper>`
51+
Exemplo de utilização: `./binary/tree-server 12345 127.0.0.1:2181`
52+
53+
- **Execução de um cliente:** `./binary/tree-client <IP Zookeeper> <Porto Zookeeper>`
54+
Exemple de utilização: `./binary/tree-client 127.0.0.1 2181`
55+
56+
- **Apagar ficheiros temporários:** `make clean`
57+
58+
#### Importante
59+
60+
Tanto o executável cliente como o executável servidor não devem ser chamados com o valor no campo IP de *"localhost"*, devendo em vez disso ser utilizado o endereço IP em notação XXX.XXX.XXX.XXX.
61+
62+
---
63+
64+
## Autores
65+
66+
Projeto realizado por Grupo 59:
67+
68+
- **João Cotralha** Nº51090
69+
- **Cláudio Esteves** Nº51098
70+

include/client_stub.h

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#ifndef _CLIENT_STUB_H
2+
#define _CLIENT_STUB_H
3+
4+
#include "data.h"
5+
#include "entry.h"
6+
#include "zookeeper/zookeeper.h"
7+
8+
/* Remote tree. A definir pelo grupo em client_stub-private.h
9+
*/
10+
struct rtree_t;
11+
12+
/* Função para estabelecer uma associação entre o cliente e o servidor,
13+
* em que address_port é uma string no formato <hostname>:<port>.
14+
* Retorna NULL em caso de erro.
15+
*/
16+
struct rtree_t *rtree_connect(const char *address_port);
17+
18+
struct rtree_t *zoo_connect(char *address_port);
19+
20+
/* Termina a associação entre o cliente e o servidor, fechando a
21+
* ligação com o servidor e libertando toda a memória local.
22+
* Retorna 0 se tudo correr bem e -1 em caso de erro.
23+
*/
24+
int rtree_disconnect(struct rtree_t *rtree);
25+
26+
/* Função para adicionar um elemento na árvore.
27+
* Se a key já existe, vai substituir essa entrada pelos novos dados.
28+
* Devolve 0 (ok, em adição/substituição) ou -1 (problemas).
29+
*/
30+
int rtree_put(struct rtree_t *rtree, struct entry_t *entry);
31+
32+
/* Função para obter um elemento da árvore.
33+
* Em caso de erro, devolve NULL.
34+
*/
35+
struct data_t *rtree_get(struct rtree_t *rtree, char *key);
36+
37+
/* Função para remover um elemento da árvore. Vai libertar
38+
* toda a memoria alocada na respetiva operação rtree_put().
39+
* Devolve: 0 (ok), -1 (key not found ou problemas).
40+
*/
41+
int rtree_del(struct rtree_t *rtree, char *key);
42+
43+
/* Devolve o número de elementos contidos na árvore.
44+
*/
45+
int rtree_size(struct rtree_t *rtree);
46+
47+
/* Função que devolve a altura da árvore.
48+
*/
49+
int rtree_height(struct rtree_t *rtree);
50+
51+
/* Devolve um array de char* com a cópia de todas as keys da árvore,
52+
* colocando um último elemento a NULL.
53+
*/
54+
char **rtree_get_keys(struct rtree_t *rtree);
55+
56+
/* Verifica se a operação identificada por op_n foi executada.
57+
* devolve 0 se nao foi executada, caso contrario 1 ou -1 em erro
58+
*/
59+
int rtree_verify(struct rtree_t *rtree,int op_n);
60+
61+
/* Liberta a memória alocada por rtree_get_keys().
62+
*/
63+
void rtree_free_keys(char **keys);
64+
65+
void connection_watcher(zhandle_t *zzh, int type, int state, const char *path, void* context);
66+
67+
static void child_watcher(zhandle_t *wzh, int type, int state, const char *zpath, void *watcher_ctx);
68+
69+
#endif

include/data.h

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#ifndef _DATA_H
2+
#define _DATA_H /* Módulo data */
3+
4+
/* Estrutura que define os dados.
5+
*/
6+
struct data_t {
7+
int datasize; /* Tamanho do bloco de dados */
8+
void *data; /* Conteúdo arbitrário */
9+
};
10+
11+
/* Função que cria um novo elemento de dados data_t e reserva a memória
12+
* necessária, especificada pelo parâmetro size
13+
*/
14+
struct data_t *data_create(int size);
15+
16+
/* Função idêntica à anterior, mas que inicializa os dados de acordo com
17+
* o parâmetro data.
18+
*/
19+
struct data_t *data_create2(int size, void *data);
20+
21+
/* Função que elimina um bloco de dados, apontado pelo parâmetro data,
22+
* libertando toda a memória por ele ocupada.
23+
*/
24+
void data_destroy(struct data_t *data);
25+
26+
/* Função que duplica uma estrutura data_t, reservando a memória
27+
* necessária para a nova estrutura.
28+
*/
29+
struct data_t *data_dup(struct data_t *data);
30+
31+
/* Função que substitui o conteúdo de um elemento de dados data_t.
32+
* Deve assegurar que destroi o conteúdo antigo do mesmo.
33+
*/
34+
void data_replace(struct data_t *data, int new_size, void *new_data);
35+
36+
#endif
37+

include/entry.h

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#ifndef _ENTRY_H
2+
#define _ENTRY_H /* Módulo entry */
3+
4+
#include "data.h"
5+
6+
/* Esta estrutura define o par {chave, valor} para a tabela
7+
*/
8+
struct entry_t {
9+
char *key; /* string, cadeia de caracteres terminada por '\0' */
10+
struct data_t *value; /* Bloco de dados */
11+
};
12+
13+
/* Função que cria uma entry, reservando a memória necessária e
14+
* inicializando-a com a string e o bloco de dados passados.
15+
*/
16+
struct entry_t *entry_create(char *key, struct data_t *data);
17+
18+
/* Função que inicializa os elementos de uma entry com o
19+
* valor NULL.
20+
*/
21+
void entry_initialize(struct entry_t *entry);
22+
23+
/* Função que elimina uma entry, libertando a memória por ela ocupada
24+
*/
25+
void entry_destroy(struct entry_t *entry);
26+
27+
/* Função que duplica uma entry, reservando a memória necessária para a
28+
* nova estrutura.
29+
*/
30+
struct entry_t *entry_dup(struct entry_t *entry);
31+
32+
/* Função que substitui o conteúdo de uma entrada entry_t.
33+
* Deve assegurar que destroi o conteúdo antigo da mesma.
34+
*/
35+
void entry_replace(struct entry_t *entry, char *new_key, struct data_t *new_value);
36+
37+
/* Função que compara duas entradas e retorna a ordem das mesmas.
38+
* Ordem das entradas é definida pela ordem das suas chaves.
39+
* A função devolve 0 se forem iguais, -1 se entry1<entry2, e 1 caso contrário.
40+
*/
41+
int entry_compare(struct entry_t *entry1, struct entry_t *entry2);
42+
43+
#endif
44+

include/message-private.h

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* ######### Grupo 59 #########
3+
* # João Cotralha Nº51090 #
4+
* # Cláudio Esteves Nº51098 #
5+
* # José Salgueiro Nº50004 #
6+
* ############################
7+
*/
8+
#ifndef _MESSAGE_PRIVATE_H
9+
#define _MESSAGE_PRIVATE_H
10+
11+
#include "client_stub.h"
12+
#include "sdmessage.pb-c.h"
13+
#include "zookeeper/zookeeper.h"
14+
15+
#include <netinet/in.h>
16+
17+
struct message_t {
18+
struct _MessageT *message_t; // buff to msg
19+
struct _MessageT bmessage_t; //msg to buff
20+
};
21+
22+
struct rtree_t{
23+
struct sockaddr_in socket;
24+
int server_flag;
25+
int descritor;
26+
};
27+
28+
void message_init(struct message_t *msg);
29+
30+
int write_all(int sock, char *buf, int len);
31+
32+
int read_all(int sock, char *buf, int len);
33+
34+
#endif

include/network_client.h

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* ######### Grupo 59 #########
3+
* # João Cotralha Nº51090 #
4+
* # Cláudio Esteves Nº51098 #
5+
* # José Salgueiro Nº50004 #
6+
* ############################
7+
*/
8+
#ifndef _NETWORK_CLIENT_H
9+
#define _NETWORK_CLIENT_H
10+
11+
#include "client_stub.h"
12+
#include "sdmessage.pb-c.h"
13+
14+
/* Esta função deve:
15+
* - Obter o endereço do servidor (struct sockaddr_in) a base da
16+
* informação guardada na estrutura rtree;
17+
* - Estabelecer a ligação com o servidor;
18+
* - Guardar toda a informação necessária (e.g., descritor do socket)
19+
* na estrutura rtree;
20+
* - Retornar 0 (OK) ou -1 (erro).
21+
*/
22+
int network_connect(struct rtree_t *rtree);
23+
24+
/* Esta função deve:
25+
* - Obter o descritor da ligação (socket) da estrutura rtree_t;
26+
* - Serializar a mensagem contida em msg;
27+
* - Enviar a mensagem serializada para o servidor;
28+
* - Esperar a resposta do servidor;
29+
* - De-serializar a mensagem de resposta;
30+
* - Retornar a mensagem de-serializada ou NULL em caso de erro.
31+
*/
32+
struct message_t *network_send_receive(struct rtree_t * rtree,
33+
struct message_t *msg);
34+
35+
/* A função network_close() fecha a ligação estabelecida por
36+
* network_connect().
37+
*/
38+
int network_close(struct rtree_t * rtree);
39+
40+
#endif

include/network_server.h

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#ifndef _NETWORK_SERVER_H
2+
#define _NETWORK_SERVER_H
3+
4+
#include "tree_skel.h"
5+
6+
/* Função para preparar uma socket de receção de pedidos de ligação
7+
* num determinado porto.
8+
* Retornar descritor do socket (OK) ou -1 (erro).
9+
*/
10+
int network_server_init(short port);
11+
12+
/* Esta função deve:
13+
* - Aceitar uma conexão de um cliente;
14+
* - Receber uma mensagem usando a função network_receive;
15+
* - Entregar a mensagem de-serializada ao skeleton para ser processada;
16+
* - Esperar a resposta do skeleton;
17+
* - Enviar a resposta ao cliente usando a função network_send.
18+
*/
19+
int network_main_loop(int listening_socket);
20+
21+
/* Esta função deve:
22+
* - Ler os bytes da rede, a partir do client_socket indicado;
23+
* - De-serializar estes bytes e construir a mensagem com o pedido,
24+
* reservando a memória necessária para a estrutura message_t.
25+
*/
26+
struct message_t *network_receive(int client_socket);
27+
28+
/* Esta função deve:
29+
* - Serializar a mensagem de resposta contida em msg;
30+
* - Libertar a memória ocupada por esta mensagem;
31+
* - Enviar a mensagem serializada, através do client_socket.
32+
*/
33+
int network_send(int client_socket, struct message_t *msg);
34+
35+
/* A função network_server_close() liberta os recursos alocados por
36+
* network_server_init().
37+
*/
38+
int network_server_close();
39+
40+
#endif

include/serialization.h

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#ifndef _SERIALIZATION_H
2+
#define _SERIALIZATION_H
3+
4+
#include "data.h"
5+
#include "entry.h"
6+
#include "tree.h"
7+
8+
/* Serializa uma estrutura data num buffer que será alocado
9+
* dentro da função. Além disso, retorna o tamanho do buffer
10+
* alocado ou -1 em caso de erro.
11+
*/
12+
int data_to_buffer(struct data_t *data, char **data_buf);
13+
14+
/* De-serializa a mensagem contida em data_buf, com tamanho
15+
* data_buf_size, colocando-a e retornando-a numa struct
16+
* data_t, cujo espaco em memoria deve ser reservado.
17+
* Devolve NULL em caso de erro.
18+
*/
19+
struct data_t *buffer_to_data(char *data_buf, int data_buf_size);
20+
21+
/* Serializa uma estrutura entry num buffer que será alocado
22+
* dentro da função. Além disso, retorna o tamanho deste
23+
* buffer ou -1 em caso de erro.
24+
*/
25+
int entry_to_buffer(struct entry_t *entry, char **entry_buf);
26+
27+
/* De-serializa a mensagem contida em entry_buf, com tamanho
28+
* entry_buf_size, colocando-a e retornando-a numa struct
29+
* entry_t, cujo espaco em memoria deve ser reservado.
30+
* Devolve NULL em caso de erro.
31+
*/
32+
struct entry_t *buffer_to_entry(char *entry_buf, int entry_buf_size);
33+
34+
/* Serializa uma estrutura tree num buffer que será alocado
35+
* dentro da função. Além disso, retorna o tamanho deste
36+
* buffer ou -1 em caso de erro.
37+
*/
38+
int tree_to_buffer(struct tree_t *tree, char **tree_buf);
39+
40+
/* De-serializa a mensagem contida em tree_buf, com tamanho
41+
* tree_buf_size, colocando-a e retornando-a numa struct
42+
* tree_t, cujo espaco em memoria deve ser reservado.
43+
* Devolve NULL em caso de erro.
44+
*/
45+
struct entry_t *buffer_to_tree(char *tree_buf, int tree_buf_size);
46+
47+
#endif

0 commit comments

Comments
 (0)