/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package io.atomix.group.election;
import io.atomix.catalyst.concurrent.Listener;
import java.util.function.Consumer;
/**
* Election context for {@link io.atomix.group.DistributedGroup}.
* <p>
* Elections are performed automatically within each {@link io.atomix.group.DistributedGroup}. As members
* are added to or removed from the group, the group will automatically elect group leaders. Each unique
* leader election is represented by a {@link Term}. The {@link Term#term()} is guaranteed to be unique
* and monotonically increasing throughout the lifetime of a group. When a leader disconnects from the
* cluster or leaves the group, the term will be increased and a new leader elected. Leaders are elected
* using a semi-random algorithm. Each instance of a group is guaranteed to see the same leader and term
* at the same <em>logical</em> time (not real time).
* <p>
* To access the current group term, use the {@link #term()}} getter.
* <pre>
* {@code
* Term currentTerm = group.election().term();
* }
* </pre>
* Clients can listen for changes in group leadership by registering an election listener via
* {@link #onElection(Consumer)}.
* <pre>
* {@code
* group.election().onElection(term -> {
* GroupMember leader = term.leader();
* });
* }
* </pre>
*
* @author <a href="http://github.com/kuujo>Jordan Halterman</a>
*/
public interface Election {
/**
* Returns the current group term.
* <p>
* If the group is undergoing a new election, the returned {@link Term} can potentially have a
* null {@link Term#leader()}. To ensure the term has a leader, either check the value or use
* an {@link #onElection(Consumer) election listener} to listen for new leaders.
*
* @return The current group term.
*/
Term term();
/**
* Registers an election listener callback.
* <p>
* The provided callback will be called each time the election is changed to a new term and a leader
* is elected. The {@link Term} provided to the election callback is guaranteed to have a monotonically
* increasing {@link Term#term() term number} and a non-null {@link Term#leader()}.
* <pre>
* {@code
* group.election().onElection(term -> {
* GroupMember leader = term.leader();
* });
* }
* </pre>
* If a leader was already elected for the current term when the callback is registered, the callback will
* be immediately called <em>before the completion of the registration</em>. Aside from this initial notification,
* all election listeners are guaranteed to see elections at the same logical time and in the same order on all
* nodes.
*
* @param callback The callback to be called when a new leader is elected.
* @return The election listener.
*/
Listener<Term> onElection(Consumer<Term> callback);
}