Exemplo n.º 1
0
uint64_t log_and_send_append_entries(struct server_context_t *s, uint64_t req_id, unsigned char *buf, size_t bufsize) {
    DBG_LOG(LOG_DEBUG, "[%s][%d] logging request for client with req_id = %llu"
            , ss[s->state], s->current_term, req_id);

    assert(s->state == LEADER);

    struct log_entry_t *prev = get_last_entry(s->log);

    uint64_t cur_index = 1;
    if(prev) {
        cur_index = prev->index + 1;
    } //else this is first entry hence cur_index = 1

    struct log_entry_t *cur = 
        append_log_entry(s->log, s->current_term, cur_index, req_id, buf, bufsize);
    if(!cur) {
        return -1;
    }
    s->last_entry = cur;

    for(int i = 0; i < s->quoram_size - 1; i++) {
        send_append_entries(s, cur_index, i);
    }
    return cur_index;
}
Exemplo n.º 2
0
static void append_entries_cb(struct data_t *result, char *err, void *data) {
    /* TODO: why we need to create and then free the data, cant we just
     * reuse the slots, especially in case of heartbeat message? */
    struct append_entries_cb_data_t *cb_data = 
            (struct append_entries_cb_data_t *)data;
    struct server_context_t *s = cb_data->s;
    int peer_index = cb_data->index;
    uint64_t first_index = cb_data->first_index;
    uint64_t last_index = cb_data->last_index;
    
    free(cb_data);

    if(err) {
        //LOG: fatal error. TODO: exit?
        DBG_LOG(LOG_DEBUG, "[%s][%d] FAIL append_entries_cb from peer_id = %d with err = %s"
                , ss[s->state], s->current_term, peer_index, err);
        return;
    }

    struct append_entries_output_t *res = get_append_entries_output(result);
    if(!res) {
        log_fatal_and_exit(s, 
            "AppendEntriesCallback: Response parsing failed");
        return;
    }
    uint64_t pair_term = res->term;
    int pair_success = res->success;
    free(res);
    if(pair_term > s->current_term) {
        set_term(s, pair_term);
        s->voted_for = 0;
        save_state(s);
        return;
    }

    if(s->state != LEADER) {
        return;
    } 
    
    if(!pair_success) {
        DBG_LOG(LOG_DEBUG, "[%s][%d] FAIL append_entries_cb from peer_id = %d"
                , ss[s->state], s->current_term, peer_index);
        //TODO: send the client prev entry
        s->next_index[peer_index] = first_index - 1;
    } else {
        DBG_LOG(LOG_DEBUG, "[%s][%d] OK append_entries_cb from peer_id = %d"
                , ss[s->state], s->current_term, peer_index);
        s->next_index[peer_index] = last_index + 1;
        s->match_index[peer_index] = last_index;

        //If there exists an N such that N > commitIndex, a majority
        //of matchIndex[i] ≥ N, and log[N].term == currentTerm: 
        //set commitIndex = N (§5.3, §5.4).
        if(s->match_index[peer_index] > s->commit_index) {
            int nOK[s->quoram_size - 1];
            for(int i = 0; i < s->quoram_size - 1; i++) {
                nOK[i] = 0;
            }
            for(int i = 0; i < s->quoram_size - 1; i++) {
                for(int j = 0; j < s->quoram_size - 1; j++) {
                    if(s->match_index[i] <= s->match_index[j]) {
                        nOK[i]++;
                    }
                }
            }
            int majority = (s->quoram_size/2);
            uint64_t N = s->commit_index;
            int minOKs = s->quoram_size;
            for(int i = 0; i < s->quoram_size - 1; i++) {
                if(nOK[i] >= majority && nOK[i] < minOKs) {
                    minOKs = nOK[i];
                    if(s->match_index[i] > N) {
                        N = s->match_index[i];
                    }
                }
            }
            if(N > s->commit_index) {
                struct log_entry_t *entryN = get_log_entry_at(s->log, N);
                //never commit entry from previous term (§5.4.2)
                if(entryN && (entryN->term == s->current_term)) {
                    s->commit_index = N;
                    commit_unapplied_entries(s, N);
                }
            }
        }
    }
    if(s->last_entry && s->last_entry->index >= s->next_index[peer_index]) {
        //send all the entries since next_index till some threshold
        //to this server
        if(send_append_entries(s, s->next_index[peer_index], peer_index)) {
            //LOG: fatal error. TODO: exit?
        }
    }
}
Exemplo n.º 3
0
bool gallocy::consensus::GallocyClient::send_append_entries() {
    gallocy::vector<LogEntry> empty;
    return send_append_entries(empty);
}