Exemple #1
0
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;
}