Beispiel #1
0
/**
 * continue_ack_reject - If we were able to reestablish connection, reintroduce
 * ourselves and redecree the attempted part as null.  Otherwise, just try
 * decreeing the part again.
 */
int
do_continue_ack_reject(GIOChannel *chan, struct paxos_acceptor *acc,
    struct paxos_continuation *k)
{
  int r;
  struct paxos_instance *inst;

  // Obtain the rejected instance.  If we can't find it, it must have been
  // sync'd away, so just return.
  inst = instance_find(&pax->ilist, k->pk_data.inum);
  if (inst == NULL) {
    return 0;
  }

  acc->pa_peer = paxos_peer_init(chan);
  if (acc->pa_peer != NULL) {
    // Account for a new live connection.
    pax->live_count++;

    // Reintroduce ourselves to the acceptor.
    ERR_RET(r, paxos_hello(acc));

    // Nullify the instance.
    inst->pi_hdr.ph_opcode = OP_DECREE;
    inst->pi_val.pv_dkind = DEC_NULL;
    inst->pi_val.pv_extra = 0;
  }

  // Reset the instance metadata, marking one vote.
  instance_init_metadata(inst);

  // Decree null if the reconnect succeeded, else redecree the part.
  return paxos_broadcast_instance(inst);
}
Beispiel #2
0
/**
 * paxos_ack_resend - Receive a resend of request data, and re-commit the
 * instance to which the request belongs.
 */
int
paxos_ack_resend(struct paxos_header *hdr, msgpack_object *o)
{
  struct paxos_instance *inst;
  struct paxos_request *req;

  // Grab the instance for which we wanted the request.  If we find that it
  // has already been cached and learned since we began our retrieval, we can
  // just return.
  //
  // Note also that an instance should only be NULL if it was committed and
  // learned and then truncated in a sync operation.
  inst = instance_find(&pax->ilist, hdr->ph_inum);
  if (inst == NULL || inst->pi_cached) {
    return 0;
  }

  // See if we already got the request.  It is possible that we received a
  // commit message for the instance before the original request broadcast
  // reached us.  However, since the instance-request mapping is one way, we
  // wait until a resend is received before committing.
  req = request_find(&pax->rcache, inst->pi_val.pv_reqid);
  if (req == NULL) {
    // Allocate a request and unpack it.
    req = g_malloc0(sizeof(*req));
    paxos_request_unpack(req, o);

    // Insert it to our request cache.
    request_insert(&pax->rcache, req);
  }

  // Commit again, now that we have the associated request.
  return paxos_commit(inst);
}
Beispiel #3
0
/**
 * proposer_ack_reject - Acknowledge an acceptor's reject.
 *
 * Increment the reject count of the appropriate Paxos instance.  If we have
 * a majority of rejects, try to reconnect to the acceptor we attempted to
 * force part.  If we are successful, re-decree null; otherwise, try the part
 * again.
 */
int
proposer_ack_reject(struct paxos_header *hdr)
{
  int r;
  struct paxos_instance *inst;
  struct paxos_acceptor *acc;
  struct paxos_continuation *k;

  // Our prepare succeeded, so we have only one possible ballot in our
  // lifetime in the system.
  assert(ballot_compare(hdr->ph_ballot, pax->ballot) == 0);

  // Find the decree of the correct instance and increment the reject count.
  inst = instance_find(&pax->ilist, hdr->ph_inum);
  inst->pi_rejects++;

  // Ignore the vote if we've already committed.
  if (inst->pi_committed) {
    return 0;
  }

  // We only reject parts.  However, we may continue to receive rejects even
  // after a majority rejects, in which case we may have re-decreed null.
  if (inst->pi_val.pv_dkind == DEC_NULL) {
    return 0;
  }
  assert(inst->pi_val.pv_dkind == DEC_PART);

  // If we have been rejected by a majority, attempt reconnection.
  if (DEATH_ADJUSTED(inst->pi_rejects) >= majority()) {
    // See if we can reconnect to the acceptor we tried to part.
    acc = acceptor_find(&pax->alist, inst->pi_val.pv_extra);
    assert(acc->pa_peer == NULL);

    // Defer computation until the client performs connection.  If it succeeds,
    // replace the part decree with a null decree; otherwise, just redecree
    // the part.  We bind the instance number of the decree as callback data.
    k = continuation_new(continue_ack_reject, acc->pa_paxid);
    k->pk_data.inum = inst->pi_hdr.ph_inum;
    ERR_RET(r, state.connect(acc->pa_desc, acc->pa_size, &k->pk_cb));
    return 0;
  }

  // If we have heard back from everyone but the accepts and rejects are tied,
  // just decree the part again.
  if (inst->pi_votes < majority() &&
      DEATH_ADJUSTED(inst->pi_rejects) < majority() &&
      inst->pi_votes + inst->pi_rejects == pax->live_count) {
    return paxos_broadcast_instance(inst);
  }

  return 0;
}