/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Jun 14, 2010
*/
package com.bigdata.quorum;
import java.util.UUID;
/**
* A non-remote interface containing <em>only</em> and <em>all</em> distributed
* quorum state change messages for this {@link QuorumMember}. These messages
* are generated by the {@link QuorumWatcher} for the {@link QuorumMember} when
* it notices the corresponding change in the distributed quorum state. Thus,
* all methods on this interface indicate <em>observed</em> state changes. The
* {@link QuorumActor} is responsible for causing changes in the distributed
* quorum state, but it DOES NOT generate these messages - that task falls to
* the {@link QuorumWatcher}.
* <p>
* Quorum members have strict preconditions on their actions, which are
* documented by the {@link QuorumActor}. In addition, {@link QuorumWatcher}
* maintains various postconditions (for example, a member leave implies a
* service leave). Together, these preconditions and postconditions imply an
* ordering over the {@link QuorumStateChangeListener}s.
* <p>
* However, because this interface reports <em>observed</em> state changes, it
* is possible that some events may occur "out of order". For example, if the
* quorum is maintained within zookeeper and a client looses its zookeeper
* connection, then zookeeper will the <i>ephemeral</i> znodes for that client.
* The <i>order</i> in which other clients observe those state changes in
* essentially arbitrary.
* <p>
* Implementations of this interface must not block in the event thread.
*
* @see QuorumMember
* @see QuorumActor
* @see QuorumWatcher
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id: QuorumStateChangeListener.java 4069 2011-01-09 20:58:02Z
* thompsonbry $
*
* @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/695">
* HAJournalServer reports "follower" but is in SeekConsensus and is not
* participating in commits (javadoc clarifications)</a>
*/
public interface QuorumStateChangeListener {
/**
* Invoked when this service is added as a quorum member.
*/
void memberAdd();
/**
* Invoked when this service is removed as a quorum member.
*/
void memberRemove();
/**
* Invoked when this service is added to the write pipeline. The service
* always enters at the of the pipeline.
*/
void pipelineAdd();
/**
* Invoked when this service is removed from the write pipeline.
*/
void pipelineRemove();
/**
* Invoked for this service when the service is already in the pipeline and
* this service becomes the first service in the write pipeline because all
* previous services in the pipeline order have been removed from the
* pipeline (failover into the leader position).
*/
void pipelineElectedLeader();
/**
* Invoked for this service when the downstream service in the write
* pipeline has changed. Services always enter at the end of the write
* pipeline, but may be removed at any position in the write pipeline.
*
* @param oldDownstreamId
* The {@link UUID} of the service which <em>was</em> downstream
* from this service in the write pipeline and <code>null</code>
* iff this service was the last service in the pipeline.
* @param newDownstreamId
* The {@link UUID} of the service which <em>is</em> downstream
* from this service in the write pipeline and <code>null</code>
* iff this service <em>is</em> the last service in the pipeline.
*/
void pipelineChange(final UUID oldDownStreamId, final UUID newDownStreamId);
/**
* Invoked for this service when the upstream service in the write pipeline
* has been removed. This hook provides an opportunity for this service to
* close out its connection with the old upstream service and to prepare to
* establish a new connection with the new downstream service.
*/
void pipelineUpstreamChange();
// void castVote(long lastCommitTime);
// void withdrawVote(long lastCommitTime);
// void setLastValidToken();
// /**
// * Invoked when <em>this</em> quorum member is elected as the quorum leader.
// */
// void electedLeader();
//
// /**
// * Invoked when <em>this</em> quorum member is elected as a quorum follower.
// * This event occurs both when the quorum meets and when a quorum member is
// * becomes synchronized with and then joins an already met quorum.
// */
// void electedFollower();
/**
* Invoked when a consensus has been achieved among <code>(k+1)/2</code>
* services concerning a shared lastCommitTime (really, this is not a
* consensus but a simple majority). This message is sent to each member
* service regardless of whether or not they participated in the consensus.
* <p>
* Once a consensus has been reached, each {@link QuorumMember} which agrees
* on that <i>lastCommitTime</i> MUST do a {@link #serviceJoin()} before the
* quorum will meet. The first quorum member to do a service join will be
* elected the leader. The remaining services to do a service join will be
* elected followers.
*
* @param lastCommitTime
* The last commit time around which a consensus was established.
*
* @see #serviceJoin()
* @see #electedLeader(long)
* @see #electedFollower(long)
* @see #lostConsensus()
*/
void consensus(final long lastCommitTime);
/**
* Invoked when the consensus is lost. Services do not withdraw their cast
* votes until a quorum breaks and a new consensus needs to be established.
* This message is sent to each member service regardless of whether or not
* they participated in the consensus.
*
* @see #consensus(long)
*/
void lostConsensus();
/**
* Invoked when this service joins the quorum.
*/
void serviceJoin();
/**
* Invoked when this service leaves the quorum.
*/
void serviceLeave();
// /**
// * Invoked for all quorum members when the leader leaves the quorum. A
// * leader leave is also a quorum break, so services can generally just
// * monitor {@link #quorumBreak()} instead of this method. Also, services
// * will generally notice a quorum break because {@link Quorum#token()} will
// * have been cleared and will in any case not be the same token under which
// * the service was operating.
// */
// void leaderLeft();
/**
* Invoked when a quorum meets. The state of the met quorum can be queried
* using the <i>token</i>. Quorum members can use this to decide whether
* they are the leader (using {@link #isLeader(long)}, joined as a
* follower (using {@link #isFollower(long)}), or do not participate
* in the quorum (this message is sent to all quorum members, so this
* service might not be part of the met qourum).
* <p>
* The following pre-conditions will be satisfied before this message is
* sent to the {@link QuorumMember}:
* <ul>
* <li>There will be at least <code>(k+1)/2</code> services which have voted
* for the same <i>lastCommitTime</i>.</li>
* <li>There will be at <code>(k+1)/2</code> services joined with the
* quorum. The {@link Quorum#getJoined() join order} will be the same
* as the {@link Quorum#getVotes()} for the services which voted for the
* <i>lastCommitTime</li> around which a consensus was formed.</li>
* <li>If this quorum member is joined with the quorum it will have observed
* its own {@link #memberAdd()}, {@link #pipelineAdd()},
* {@link #consensus(long)}, and {@link #serviceJoin()} events.</li>
* <li>The joined services will be arranged in a write pipeline, with the
* leader at the head of that pipeline.</li>
* </ul>
* <p>
* When control returns from this method, the following post-conditions
* should be true:
* <ul>
* <li>The service should be prepared to accept reads.</li>
* <li>If the service was elected as the quorum leader, then it should be
* prepared to accept writes.</li>
* </ul>
* If the {@link QuorumMember} is joined with the quorum but it can not
* satisfy these post-conditions, then it must
* {@link QuorumActor#serviceLeave() leave} the {@link Quorum}.
*
* @param token
* The newly assigned quorum token.
* @param leaderId
* The {@link UUID} of the service which was elected to be the
* quorum leader. This information is only valid for the scope of
* the accompanying quorum token. (The leaderId may be obtained
* from {@link #getLeader(long)} at any time for a met quorum.)
*/
void quorumMeet(long token, UUID leaderId);
/**
* Invoked when a quorum breaks. The service MUST handle handle this event
* by (a) doing an abort() which will any buffered writes and reload their
* current root block; and (b) casting a vote for their current commit time.
* Once a consensus is reached on the current commit time, services will be
* joined in the vote order, a new leader will be elected, and the quorum
* will meet again. This message is sent to all member services, regardless
* of whether they were joined with the met quorum.
*/
void quorumBreak();
}