/** * acceptor_ack_refuse - Resolve an acceptor's claim that we do not know * the true proposer. * * If we send a request to someone who is not the proposer, but identifying * them as the proposer, we will receive a refuse. Since the correctness * of the Paxos protocol guarantees that the acceptor list has a consistent * total ordering across the system, receiving a refuse means that there is * someone more fitting to be proposer than the acceptor we identified. * * Note, as with ack_redirect, that it is possible we noticed a proposer * failure and sent our request to the new proposer correctly before the new * proposer themselves recognized the failure. */ int acceptor_ack_refuse(struct paxos_header *hdr, msgpack_object *o) { int r; msgpack_object *p; struct paxos_acceptor *acc; struct paxos_continuation *k; // Check whether, since we sent our request, we have already found a more // suitable proposer, possibly due to another redirect, in which case we // can ignore this one. if (pax->proposer->pa_paxid <= hdr->ph_inum) { return 0; } // Pull out the acceptor struct corresponding to the purported proposer and // try to reconnect. Note that we should have already set the pa_peer of // this acceptor to NULL to indicate the lost connection. acc = acceptor_find(&pax->alist, hdr->ph_inum); assert(acc->pa_peer == NULL); // Defer computation until the client performs connection. If it succeeds, // resend the request. We bind the request ID as callback data. k = continuation_new(continue_ack_refuse, acc->pa_paxid); assert(o->type == MSGPACK_OBJECT_ARRAY); p = o->via.array.ptr + 1; paxos_value_unpack(&k->pk_data.req.pr_val, p++); ERR_RET(r, state.connect(acc->pa_desc, acc->pa_size, &k->pk_cb)); return 0; }
/** * paxos_ack_retrieve - Acknowledge a retrieve. * * This basically just unpacks and wraps a resend. */ int paxos_ack_retrieve(struct paxos_header *hdr, msgpack_object *o) { paxid_t paxid; msgpack_object *p; struct paxos_value val; struct paxos_request *req; struct paxos_acceptor *acc; // Make sure the payload is well-formed. assert(o->type == MSGPACK_OBJECT_ARRAY); assert(o->via.array.size == 2); p = o->via.array.ptr; // Unpack the retriever's ID and the value being retrieved. paxos_paxid_unpack(&paxid, p++); paxos_value_unpack(&val, p++); // Retrieve the request. assert(request_needs_cached(val.pv_dkind)); req = request_find(&pax->rcache, val.pv_reqid); if (req != NULL) { // If we have the request, look up the recipient and resend. acc = acceptor_find(&pax->alist, paxid); return paxos_resend(acc, hdr, req); } else { // If we don't have the request either, just return. return 0; } }
void paxos_request_unpack(struct paxos_request *req, msgpack_object *o) { msgpack_object *p; // Make sure the input is well-formed. assert(o->type == MSGPACK_OBJECT_ARRAY); assert(o->via.array.size == 2); // Unpack the value. p = o->via.array.ptr; paxos_value_unpack(&req->pr_val, p++); // Unpack the raw data. assert(p->type == MSGPACK_OBJECT_RAW); req->pr_size = p->via.raw.size; req->pr_data = g_memdup(p->via.raw.ptr, p->via.raw.size); }
void paxos_instance_unpack(struct paxos_instance *inst, msgpack_object *o) { msgpack_object *p; // Make sure the input is well-formed. assert(o->type == MSGPACK_OBJECT_ARRAY); assert(o->via.array.size == 3); p = o->via.array.ptr; // Unpack the header, committed flag, and value. paxos_header_unpack(&inst->pi_hdr, p++); assert(p->type == MSGPACK_OBJECT_BOOLEAN); inst->pi_committed = (p++)->via.boolean; paxos_value_unpack(&inst->pi_val, p++); // Set everything else to 0. inst->pi_cached = false; inst->pi_learned = false; inst->pi_votes = 0; inst->pi_rejects = 0; }