Example #1
0
File: raft.c Project: jnpkrn/booth
static int process_UPDATE (
		struct ticket_config *tk,
		struct booth_site *sender,
		struct booth_site *leader,
		struct boothc_ticket_msg *msg
	       )
{
	if (is_owned(tk) && sender != tk->leader) {
		tk_log_warn("different leader %s wants to update "
				"our ticket, sending reject",
			site_string(leader));
		return send_reject(sender, tk, RLT_TERM_OUTDATED, msg);
	}

	tk_log_debug("leader %s wants to update our ticket",
			site_string(leader));

	become_follower(tk, msg);
	set_leader(tk, leader);
	ticket_write(tk);

	/* run ticket_cron if the ticket expires */
	set_ticket_wakeup(tk);

	return send_msg(OP_ACK, tk, sender, msg);
}
Example #2
0
/** Try to get the ticket for the local site.
 * */
int do_grant_ticket(struct ticket_config *tk, int options)
{
	int rv;

	tk_log_info("granting ticket");

	if (tk->leader == local)
		return RLT_SUCCESS;
	if (is_owned(tk))
		return RLT_OVERGRANT;

	set_future_time(&tk->delay_commit, tk->term_duration + tk->acquire_after);

	if (options & OPT_IMMEDIATE) {
		tk_log_warn("granting ticket immediately! If there are "
				"unreachable sites, _hope_ you are sure that they don't "
				"have the ticket!");
		time_reset(&tk->delay_commit);
	}

	rv = acquire_ticket(tk, OR_ADMIN);
	if (rv) {
		time_reset(&tk->delay_commit);
		return rv;
	} else {
		return RLT_MORE;
	}
}
Example #3
0
File: raft.c Project: jnpkrn/booth
/* For follower. */
static int answer_HEARTBEAT (
		struct ticket_config *tk,
		struct booth_site *sender,
		struct booth_site *leader,
		struct boothc_ticket_msg *msg
	       )
{
	uint32_t term;

	term = ntohl(msg->ticket.term);
	tk_log_debug("heartbeat from leader: %s, have %s; term %d vs %d",
			site_string(leader), ticket_leader_string(tk),
			term, tk->current_term);

	if (term < tk->current_term) {
		if (sender == tk->leader) {
			tk_log_info("trusting leader %s with a lower term (%d vs %d)",
				site_string(leader), term, tk->current_term);
		} else if (is_owned(tk)) {
			tk_log_warn("different leader %s with a lower term "
					"(%d vs %d), sending reject",
				site_string(leader), term, tk->current_term);
			return send_reject(sender, tk, RLT_TERM_OUTDATED, msg);
		}
	}

	/* got heartbeat, no rejects expected anymore */
	tk->expect_more_rejects = 0;

	/* Needed? */
	newer_term(tk, sender, leader, msg, 0);

	become_follower(tk, msg);
	/* Racy??? */
	assert(sender == leader || !leader);

	set_leader(tk, leader);

	/* Ack the heartbeat (we comply). */
	return send_msg(OP_ACK, tk, sender, msg);
}
Example #4
0
/** Try to get the ticket for the local site.
 * */
int do_grant_ticket(struct ticket_config *tk, int options)
{
	int rv;

	tk_log_info("granting ticket");

	if (tk->leader == local)
		return RLT_SUCCESS;
	if (is_owned(tk)) {
		if (is_manual(tk) && (options & OPT_IMMEDIATE)) {
			/* -F flag has been used while granting a manual ticket.
			 * The ticket will be granted and may end up being granted
			 * on multiple sites */
			tk_log_warn("manual ticket forced to be granted! be aware that "
					"you may end up having two sites holding the same manual "
					"ticket! revoke the ticket from the unnecessary site!");
		} else {
			return RLT_OVERGRANT;
		}
	}

	set_future_time(&tk->delay_commit, tk->term_duration + tk->acquire_after);

	if (options & OPT_IMMEDIATE) {
		tk_log_warn("granting ticket immediately! If there are "
				"unreachable sites, _hope_ you are sure that they don't "
				"have the ticket!");
		time_reset(&tk->delay_commit);
	}

	rv = acquire_ticket(tk, OR_ADMIN);
	if (rv) {
		time_reset(&tk->delay_commit);
		return rv;
	} else {
		return RLT_MORE;
	}
}
Example #5
0
File: raft.c Project: jnpkrn/booth
int raft_answer(
		struct ticket_config *tk,
		struct booth_site *sender,
		struct booth_site *leader,
		struct boothc_ticket_msg *msg
	       )
{
	int cmd, req;
	int rv;

	rv = 0;
	cmd = ntohl(msg->header.cmd);
	req = ntohl(msg->header.request);

	if (req)
		tk_log_debug("got %s (req %s) from %s",
				state_to_string(cmd),
				state_to_string(req),
				site_string(sender));
	else
		tk_log_debug("got %s from %s",
				state_to_string(cmd),
				site_string(sender));

	/* don't process tickets with invalid term
	 */
	if (cmd != OP_STATUS &&
			msg_term_invalid(tk, sender, leader, msg))
		return 0;


	switch (cmd) {
	case OP_REQ_VOTE:
		rv = answer_REQ_VOTE(tk, sender, leader, msg);
		break;
	case OP_VOTE_FOR:
		rv = process_VOTE_FOR(tk, sender, leader, msg);
		break;
	case OP_ACK:
		if (tk->leader == local &&
				tk->state == ST_LEADER)
			rv = process_ACK(tk, sender, leader, msg);
		break;
	case OP_HEARTBEAT:
		if ((tk->leader != local || !term_time_left(tk)) &&
				(tk->state == ST_INIT || tk->state == ST_FOLLOWER ||
				tk->state == ST_CANDIDATE))
			rv = answer_HEARTBEAT(tk, sender, leader, msg);
		else {
			tk_log_warn("unexpected message %s, from %s",
				state_to_string(cmd),
				site_string(sender));
			if (ticket_seems_ok(tk))
				send_reject(sender, tk, RLT_TERM_STILL_VALID, msg);
			rv = -EINVAL;
		}
		break;
	case OP_UPDATE:
		if (((tk->leader != local && tk->leader == leader) || !is_owned(tk)) &&
				(tk->state == ST_INIT || tk->state == ST_FOLLOWER ||
				tk->state == ST_CANDIDATE)) {
			rv = process_UPDATE(tk, sender, leader, msg);
		} else {
			tk_log_warn("unexpected message %s, from %s",
				state_to_string(cmd),
				site_string(sender));
			if (ticket_seems_ok(tk))
				send_reject(sender, tk, RLT_TERM_STILL_VALID, msg);
			rv = -EINVAL;
		}
		break;
	case OP_REJECTED:
		rv = process_REJECTED(tk, sender, leader, msg);
		break;
	case OP_REVOKE:
		rv = process_REVOKE(tk, sender, leader, msg);
		break;
	case OP_MY_INDEX:
		rv = process_MY_INDEX(tk, sender, leader, msg);
		break;
	case OP_STATUS:
		if (!tk->in_election)
			rv = send_msg(OP_MY_INDEX, tk, sender, msg);
		break;
	default:
		tk_log_error("unknown message %s, from %s",
			state_to_string(cmd), site_string(sender));
		rv = -EINVAL;
	}
	return rv;
}
Example #6
0
int list_ticket(char **pdata, unsigned int *len)
{
	struct ticket_config *tk;
	char timeout_str[64];
	char pending_str[64];
	char *data, *cp;
	int i, alloc;
	time_t ts;

	*pdata = NULL;
	*len = 0;

	alloc = booth_conf->ticket_count * (BOOTH_NAME_LEN * 2 + 128);
	data = malloc(alloc);
	if (!data)
		return -ENOMEM;

	cp = data;
	foreach_ticket(i, tk) {
		if (is_time_set(&tk->term_expires)) {
			ts = wall_ts(&tk->term_expires);
			strftime(timeout_str, sizeof(timeout_str), "%F %T",
					localtime(&ts));
		} else
			strcpy(timeout_str, "INF");

		if (tk->leader == local && is_time_set(&tk->delay_commit)
				&& !is_past(&tk->delay_commit)) {
			ts = wall_ts(&tk->delay_commit);
			strcpy(pending_str, " (commit pending until ");
			strftime(pending_str + strlen(" (commit pending until "),
					sizeof(pending_str) - strlen(" (commit pending until ") - 1,
					"%F %T", localtime(&ts));
			strcat(pending_str, ")");
		} else
			*pending_str = '\0';

		cp += snprintf(cp,
				alloc - (cp - data),
				"ticket: %s, leader: %s",
				tk->name,
				ticket_leader_string(tk));

		if (is_owned(tk)) {
			cp += snprintf(cp,
					alloc - (cp - data),
					", expires: %s%s\n",
					timeout_str,
					pending_str);
		} else {
			cp += snprintf(cp, alloc - (cp - data), "\n");
		}

		if (alloc - (cp - data) <= 0) {
			free(data);
			return -ENOMEM;
		}
	}

	*pdata = data;
	*len = cp - data;

	return 0;
}