Exemple #1
0
static void log_reacquire_reason(struct ticket_config *tk)
{
	int valid;
	const char *where_granted = "\0";
	char buff[64];

	valid = is_time_set(&tk->term_expires) && !is_past(&tk->term_expires);

	if (tk->leader == local) {
		where_granted = "granted here";
	} else {
		snprintf(buff, sizeof(buff), "granted to %s",
			site_string(tk->leader));
		where_granted = buff;
	}

	if (!valid) {
		tk_log_warn("%s, but not valid "
			"anymore (will try to reacquire)", where_granted);
	}
	if (tk->is_granted && tk->leader != local) {
		if (tk->leader && tk->leader != no_leader) {
			tk_log_error("granted here, but also %s, "
				"that's really too bad (will try to reacquire)",
				where_granted);
		} else {
			tk_log_warn("granted here, but we're "
				"not recorded as the grantee (will try to reacquire)");
		}
	}
}
Exemple #2
0
/* is it safe to commit the grant?
 * if we didn't hear from all sites on the initial grant, we may
 * need to delay the commit
 *
 * TODO: investigate possibility to devise from history whether a
 * missing site could be holding a ticket or not
 */
static int ticket_dangerous(struct ticket_config *tk)
{
	int tdiff;
	/* we may be invoked often, don't spam the log unnecessarily
	 */
	static int no_log_delay_msg;

	if (!is_time_set(&tk->delay_commit))
		return 0;

	if (is_past(&tk->delay_commit) || all_sites_replied(tk)) {
		if (tk->leader == local) {
			tk_log_info("%s, committing to CIB",
				is_past(&tk->delay_commit) ?
				"ticket delay expired" : "all sites replied");
		}
		time_reset(&tk->delay_commit);
		no_log_delay_msg = 0;
		return 0;
	}

	tdiff = time_left(&tk->delay_commit);
	tk_log_debug("delay ticket commit for another " intfmt(tdiff));
	if (!no_log_delay_msg) {
		tk_log_info("delaying ticket commit to CIB for " intfmt(tdiff));
		tk_log_info("(or all sites are reached)");
		no_log_delay_msg = 1;
	}

	return 1;
}
Exemple #3
0
static void won_elections(struct ticket_config *tk)
{
	set_leader(tk, local);
	set_state(tk, ST_LEADER);

	set_ticket_expiry(tk, tk->term_duration);
	time_reset(&tk->election_end);
	tk->voted_for = NULL;

	if (is_time_set(&tk->delay_commit) && all_sites_replied(tk)) {
		time_reset(&tk->delay_commit);
		tk_log_debug("reset delay commit as all sites replied");
	}

	save_committed_tkt(tk);

	ticket_broadcast(tk, OP_HEARTBEAT, OP_ACK, RLT_SUCCESS, 0);
	tk->ticket_updated = 0;
}
Exemple #4
0
int new_election(struct ticket_config *tk,
	struct booth_site *preference, int update_term, cmd_reason_t reason)
{
	struct booth_site *new_leader;

	if (local->type != SITE)
		return 0;

	if ((is_reason(OR_TKT_LOST, tk) || is_reason(OR_STEPDOWN, tk)) &&
			check_attr_prereq(tk, GRANT_AUTO)) {
		tk_log_info("attribute prerequisite not met, "
			"not starting elections");
		return 0;
	}

	/* elections were already started, but not yet finished/timed out */
	if (is_time_set(&tk->election_end) && !is_past(&tk->election_end))
		return 1;

	if (ANYDEBUG) {
		int tdiff;
		if (is_time_set(&tk->election_end)) {
			tdiff = -time_left(&tk->election_end);
			tk_log_debug("starting elections, previous finished since " intfmt(tdiff));
		} else {
			tk_log_debug("starting elections");
		}
		tk_log_debug("elections caused by %s %s",
				state_to_string(reason),
				reason == OR_AGAIN ? state_to_string(tk->election_reason) : "" );
	}

	/* §5.2 */
	/* If there was _no_ answer, don't keep incrementing the term number
	 * indefinitely. If there was no peer, there'll probably be no one
	 * listening now either. However, we don't know if we were
	 * invoked due to a timeout (caller does).
	 */
	/* increment the term only if either the current term was
	 * valid or if there was a tie (in that case update_term > 1)
	 */
	if ((update_term > 1) ||
		(update_term && tk->last_valid_tk &&
			tk->last_valid_tk->current_term >= tk->current_term)) {
		/* save the previous term, we may need to send out the
		 * MY_INDEX message */
		if (tk->state != ST_CANDIDATE) {
			save_committed_tkt(tk);
		}
		tk->current_term++;
	}

	set_future_time(&tk->election_end, tk->timeout);
	tk->in_election = 1;

	tk_log_info("starting new election (term=%d)",
			tk->current_term);
	clear_election(tk);

	if(preference)
		new_leader = preference;
	else
		new_leader = (local->type == SITE) ? local : NULL;
	record_vote(tk, local, new_leader);
	tk->voted_for = new_leader;

	set_state(tk, ST_CANDIDATE);

	/* some callers may want just to repeat on timeout */
	if (reason == OR_AGAIN) {
		reason = tk->election_reason;
	} else {
		tk->election_reason = reason;
	}

	ticket_broadcast(tk, OP_REQ_VOTE, OP_VOTE_FOR, RLT_SUCCESS, reason);
	add_random_delay(tk);
	return 0;
}
Exemple #5
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;
}