void session_destroy(struct paxos_session *session) { // Wipe all our lists. acceptor_container_destroy(&pax->alist); acceptor_container_destroy(&pax->adefer); continuation_container_destroy(&pax->clist); instance_container_destroy(&pax->ilist); instance_container_destroy(&pax->idefer); request_container_destroy(&pax->rcache); g_free(session); }
/** * continue_ack_redirect - If we were able to reestablish connection with the * purported proposer, relinquish our proposership, clear our defer list, * and reintroduce ourselves. Otherwise, try preparing again. */ int do_continue_ack_redirect(GIOChannel *chan, struct paxos_acceptor *acc, struct paxos_continuation *k) { // Sanity check the choice of acc. assert(acc->pa_paxid < pax->self_id); // If connection to the acceptor has already been reestablished, we should // no longer be the proposer and we can simply return. if (acc->pa_peer != NULL) { assert(!is_proposer()); return 0; } // Free the old prepare regardless of whether reconnection succeeded. g_free(pax->prep); pax->prep = NULL; // Register the reconnection; on failure, reprepare. acc->pa_peer = paxos_peer_init(chan); if (acc->pa_peer != NULL) { // Account for a new acceptor. pax->live_count++; // We update the proposer only if we have not reconnected to an even // higher-ranked acceptor. if (acc->pa_paxid < pax->proposer->pa_paxid) { pax->proposer = acc; } // Destroy the defer list; we're finished trying to prepare. // XXX: Do we want to somehow pass it to the real proposer? How do we // know which requests were made for us? instance_container_destroy(&pax->idefer); // Say hello. return paxos_hello(acc); } else { // Prepare again, continuing to append to the defer list. return proposer_prepare(NULL); } }
/** * continue_ack_refuse - If we were able to reestablish connection with the * purported proposer, reset our proposer and reintroduce ourselves. */ int do_continue_ack_refuse(GIOChannel *chan, struct paxos_acceptor *acc, struct paxos_continuation *k) { int r = 0; struct paxos_header hdr; struct paxos_request *req; struct yakyak yy; // If we are the proposer and have finished preparing, anyone higher-ranked // than we are is dead to us. However, their parts may not yet have gone // through, so we make sure to ignore attempts at reconnection. if (is_proposer() && pax->prep == NULL) { return 0; } // Register the reconnection. acc->pa_peer = paxos_peer_init(chan); if (acc->pa_peer != NULL) { // Account for a new acceptor. pax->live_count++; // Free any prep we have. Although we dispatch as an acceptor when we // acknowledge a refuse, when the acknowledgement continues here, we may // have become the proposer. Thus, if we are preparing, we should just // give up. If the acceptor we are reconnecting to fails, we'll find // out about the drop and then reprepare. g_free(pax->prep); pax->prep = NULL; instance_container_destroy(&pax->idefer); // Say hello. ERR_ACCUM(r, paxos_hello(acc)); if (acc->pa_paxid < pax->proposer->pa_paxid) { // Update the proposer only if we have not reconnected to an even // higher-ranked acceptor. pax->proposer = acc; // Resend our request. // XXX: What about the problematic case where A is connected to B, B // thinks it's the proposer and accepts A's request, but in fact B is not // the proposer and C, the real proposer, gets neither of their requests? header_init(&hdr, OP_REQUEST, pax->proposer->pa_paxid); req = request_find(&pax->rcache, k->pk_data.req.pr_val.pv_reqid); if (req == NULL) { req = &k->pk_data.req; } yakyak_init(&yy, 2); paxos_header_pack(&yy, &hdr); paxos_request_pack(&yy, req); ERR_ACCUM(r, paxos_send_to_proposer(&yy)); yakyak_destroy(&yy); } } return r; }