/* TODO: check if test case is needed */ void TestRaft_follower_recv_appendentries_updates_currentterm_if_term_gt_currentterm( CuTest * tc) { msg_appendentries_t ae; msg_appendentries_response_t aer; void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); /* older currentterm */ raft_set_current_term(r, 1); CuAssertTrue(tc, -1 == raft_get_current_leader(r)); /* newer term for appendentry */ memset(&ae, 0, sizeof(msg_appendentries_t)); /* no prev log idx */ ae.prev_log_idx = 0; ae.term = 2; /* appendentry has newer term, so we change our currentterm */ raft_recv_appendentries(r, 1, &ae, &aer); CuAssertTrue(tc, 1 == aer.success); /* term has been updated */ CuAssertTrue(tc, 2 == raft_get_current_term(r)); /* and leader has been updated */ CuAssertTrue(tc, 1 == raft_get_current_leader(r)); }
/* 5.1 */ void TestRaft_follower_recv_appendentries_reply_false_if_term_less_than_currentterm( CuTest * tc) { msg_appendentries_t ae; msg_appendentries_response_t aer, *aerr; void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); void *sender = sender_new(NULL); /* no leader known at this point */ CuAssertTrue(tc, -1 == raft_get_current_leader(r)); /* term is low */ memset(&ae, 0, sizeof(msg_appendentries_t)); ae.term = 1; /* higher current term */ raft_set_current_term(r, 5); raft_recv_appendentries(r, 1, &ae, &aer); aerr = sender_poll_msg_data(sender); CuAssertTrue(tc, NULL != aerr); CuAssertTrue(tc, 0 == aerr->success); /* rejected appendentries doesn't change the current leader. */ CuAssertTrue(tc, -1 == raft_get_current_leader(r)); }
/** HTTP POST entry point for receiving entries from client * Provide the user with an ID */ static int __http_get_id(h2o_handler_t *self, h2o_req_t *req) { static h2o_generator_t generator = { NULL, NULL }; if (!h2o_memis(req->method.base, req->method.len, H2O_STRLIT("POST"))) return -1; /* redirect to leader if needed */ int leader = raft_get_current_leader(sv->raft); if (-1 == leader) { return h2oh_respond_with_error(req, 503, "Leader unavailable"); } else if (leader != sv->node_idx) { raft_node_t* node = raft_get_node(sv->raft, leader); peer_connection_t* leader_conn = raft_node_get_udata(node); char leader_url[LEADER_URL_LEN]; static h2o_generator_t generator = { NULL, NULL }; static h2o_iovec_t body = { .base = "", .len = 0 }; req->res.status = 301; req->res.reason = "Moved Permanently"; h2o_start_response(req, &generator); snprintf(leader_url, LEADER_URL_LEN, "http://%s:%d/", inet_ntoa(leader_conn->addr.sin_addr), leader_conn->http_port); h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_LOCATION, leader_url, strlen(leader_url)); h2o_send(req, &body, 1, 1); return 0; } int e; unsigned int ticket = __generate_ticket(); msg_entry_t entry; entry.id = rand(); entry.data.buf = (void*)&ticket; entry.data.len = sizeof(ticket); uv_mutex_lock(&sv->raft_lock); msg_entry_response_t r; e = raft_recv_entry(sv->raft, sv->node_idx, &entry, &r); if (0 != e) return h2oh_respond_with_error(req, 500, "BAD"); /* block until the entry is committed */ int done = 0; do { uv_cond_wait(&sv->appendentries_received, &sv->raft_lock); e = raft_msg_entry_response_committed(sv->raft, &r); switch (e) { case 0: /* not committed yet */ break; case 1: done = 1; uv_mutex_unlock(&sv->raft_lock); break; case -1: uv_mutex_unlock(&sv->raft_lock); return h2oh_respond_with_error(req, 400, "TRY AGAIN"); } } while (!done); /* serialize ID */ char id_str[100]; h2o_iovec_t body; sprintf(id_str, "%d", entry.id); body = h2o_iovec_init(id_str, strlen(id_str)); req->res.status = 200; req->res.reason = "OK"; h2o_start_response(req, &generator); h2o_send(req, &body, 1, 1); return 0; }