/******************************************************************************* Arquivo: handlers.c Autor: Gustavo Aschwanden Soviersovski Função: Contém todas as funções responsáveis pela tomada de ação para quando um nodo falha, recupera, testa outro nodo ou faz broadcast Última Edição em: 31/05/2019 *******************************************************************************/ #include #include #include "handlers.h" #include "smpl.h" #include "nodo.h" #include "cis.h" #include "loggers.h" #include "constants.h" extern tnodo *nodo; //Variáveis globais para contagem de teste e latência int evtTestCounter, latency, evtHappened; extern int *globalState; //Função responsável por receber informações do state de outro nodo, caso a informação seja mais recente (state[i] seja maior) int recebeNovidades(int *myState, int *otherState, int n, int informante) { int i, updated = 0; for (i = 0; i < n; i++) if (myState[i] < otherState[i]) { if (myState[i] % 2 != otherState[i] % 2) logNovidade(informante, i, otherState[i]); myState[i] = otherState[i]; updated = 1; } return updated; } //Retorna o lg de n, usado para saber até qual s deve calcular o C(i,s) int lg(int n) { int ret = 1; while (n/2 > 1) { ret++; n /= 2; } return ret; } //Determina quais nodos devem ser testados pelo nodo com id = token int determineTests(int *toTests, int token, int n) { node_set *Cis = NULL; int i, j, testTable[n][n], s; int found, numNodos = 0; //Zera vetor de resultados e matriz de testes for (i = 0; i < n; i++) { toTests[i] = 0; for (j = 0; j < n; j++) testTable[i][j] = 0; } //Para cada nodo for (i = 0; i < n; i++) { for (s = 1; s <= lg(n); s++) { //Desaloca lixo dos cálculos anteriores if (Cis) set_free(Cis); //Obtem o C(i,s) desse nodo Cis = cis(i, s); found = 0; //Percorre os nodos de C(i,s) até encontrar o primeiro sem falha for (j = 0; j < Cis->size && !found; j++) if (nodo[token].state[Cis->nodes[j]] % 2 == 0) { //Preenche com 1 na matriz[nodo1][nodo2] se nodo 1 testa nodo2 testTable[Cis->nodes[j]][i] = 1; found = 1; } } } //Percorre a linha do nodo copiando todos os ids que o nodo testa para o vetor de resultados for (i = 0, j = 0; i < n; i++) if (testTable[token][i]) { toTests[j] = i; j++; } set_free(Cis); return j; } //Determina e executa todos os testes, tomando as ações correspondentes em cada caso int executeTest(int token, int n) { int toTests[n]; int i, updated, numTests, tmp; updated = 0; numTests = determineTests(toTests, token , n); logTest(token, numTests, toTests); //Para cada nodo a testar for (i = 0; i < numTests; i++) { //Se o nodo testado está falho, mas a informação de state diz que ele está ok if (status(nodo[toTests[i]].id) != 0 && nodo[token].state[toTests[i]] % 2 == 0) { logFalhaDescoberta(toTests[i]); nodo[token].state[toTests[i]]++; updated = 1; } //Se o nodo testado está ok, mas a informação de state diz que ele está falho if (status(nodo[toTests[i]].id) == 0 && abs(nodo[token].state[toTests[i]]) % 2 == 1) { if(nodo[token].state[toTests[i]] != -1) logRepairDescoberto(toTests[i]); nodo[token].state[toTests[i]]++; updated = 1; } //Se o nodo testado está ok if (status(nodo[toTests[i]].id) == 0) { tmp = recebeNovidades(nodo[token].state, nodo[toTests[i]].state, n, toTests[i]); updated = updated ? updated : tmp; } } evtTestCounter += numTests; return updated; } //Verifica se o vetor state do nodo está condizente com o vetor global que mantém o estado real de todos os nodos int awareOfEvent(int *state, int n) { int i; for (i = 0; i < n; i++) if (state[i] != globalState[i]) return 0; return 1; } //Toma as ações cabíveis quando um teste foi agendado para o nodo com id = token void testHandler(int token, int n){ int i, rodadaAcabou; int updated; //Só executa o teste caso o nodo esteja ok if (status(nodo[token].id) == 0) { //Atualiza o dado informando que ele testou nessa rodada nodo[token].testouNaRodada = DONE; rodadaAcabou = 1; //Se todos testaram, inicia uma nova rodada e incrementa a latência for (i = 0; i < n; i++) { if (nodo[i].testouNaRodada == UNDONE) rodadaAcabou = 0; } if (rodadaAcabou) { for (i = 0; i < n; i++) if (nodo[i].testouNaRodada == DONE) nodo[i].testouNaRodada = UNDONE; latency++; } //Executa os testes propriamente ditos updated = executeTest(token, n); //Se o nodo sabe de todos os eventos que ocorreram até então atualiza seu estado para notificado if (awareOfEvent(nodo[token].state, n)) nodo[token].notified = NOTIFIED; //Agenda o próximo teste schedule(TEST, 10.0, token); //Verifica se o diagnostico se completou e faz o log em caso positivo if (evtHappened) logIfCompleteDiagnosis(n, rodadaAcabou); } } //Toma as ações cabí­veis quando o nodo de id = token falha void faultHandler(int token, int n){ static int r, i; //Falha o nodo efetivamente r = request(nodo[token].id, token, 0); if (r != 0) { puts("Nao foi possivel falhar o nodo"); exit(1); } //Reseta o contador de testes desde o último evento e a latencia evtTestCounter = 0; latency = 0; //Muda seu status localmente e no vetor global para falho globalState[token]++; nodo[token].notified = DOWN; nodo[token].testouNaRodada = DOWN; nodo[token].state[token]++; //Atualiza todos os outros nodos para nao notificados e nao testaram na rodada for (i = 0; i < n; i++) { if (i != token) { if (nodo[i].notified == NOTIFIED) nodo[i].notified = UNNOTIFIED; if (nodo[i].testouNaRodada == DONE) nodo[i].testouNaRodada = UNDONE; } } evtHappened = 1; } //Toma as ações cabí­veis quando o nodo de id = token falha void repairHandler(int token, int n){ int i; //Recupera o nodo efetivamente e agenda seu próximo teste release(nodo[token].id, token); schedule(TEST, 10.0, token); //Reseta o contador de testes desde o último evento e a latencia evtTestCounter = 0; latency = 0; //Muda seu status localmente e no vetor global para ok globalState[token]++; nodo[token].testouNaRodada = DONE; nodo[token].state[token]++; //Caso o nodo não saiba de tudo o que ocorreu desde sua queda atualiza seu estado para não notificado if (awareOfEvent(nodo[token].state, n)) nodo[token].notified = NOTIFIED; else { nodo[token].notified = UNNOTIFIED; nodo[token].testouNaRodada = UNDONE; } //Atualiza todos os outros nodos para nao notificados e nao testaram na rodada for (i = 0; i < n; i++) { if (i != token) { if (nodo[i].notified == NOTIFIED) nodo[i].notified = UNNOTIFIED; if (nodo[i].testouNaRodada == DONE) nodo[i].testouNaRodada = UNDONE; } } evtHappened = 1; } //Toma as ações cabíveis quando o nodo de id = src faz broadcast void broadcastHandler(int src, int smax) { int s, i, found; node_set *Cis = NULL; //Para cada cluster do nodo for (s = 1; s <= smax; s++) { Cis = cis(src, s); found = 0; //Procura pelo primeiro nodo sem falha no cluster for (i = 0; i < Cis->size && !found; i++) { if (nodo[src].state[Cis->nodes[i]] % 2 == 0) { //Manda a mensagem para o nodo, o qual irá executar o mesmo procedimento para 1 até s-1 sendBroadcastMsg(src, Cis->nodes[i]); broadcastHandler(Cis->nodes[i], s - 1); found = 1; } } set_free(Cis); } }