com.bigdata.quorum.AbstractQuorumMember Maven / Gradle / Ivy
/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
[email protected]
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 2, 2010
*/
package com.bigdata.quorum;
import java.rmi.Remote;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* Abstract base class for a {@link QuorumMember}.
*
* @author Bryan Thompson
* @version $Id$
*/
abstract public class AbstractQuorumMember extends
AbstractQuorumClient implements QuorumMember {
private final UUID serviceId;
protected AbstractQuorumMember(final String logicalServiceId,
final UUID serviceId) {
super(logicalServiceId);
if (serviceId == null)
throw new IllegalArgumentException();
this.serviceId = serviceId;
}
@Override
public S getLeader(final long token) {
final Quorum,?> q = getQuorum();
q.assertQuorum(token);
final UUID leaderId = q.getLeaderId();
if (leaderId == null) {
q.assertQuorum(token);
throw new AssertionError();
}
return getService(leaderId);
}
@Override
abstract public S getService(UUID serviceId);
@Override
public UUID getServiceId() {
return serviceId;
}
/**
* Return the actor for this {@link QuorumMember} (it is allocated by
* {@link AbstractQuorum#start(QuorumClient)}).
*/
@Override
public QuorumActor> getActor() {
// Note: This causes a compiler error on CI builds w/ JDK1.1.6_17.
// return (QuorumActor>) getQuorum().getActor();
// return (QuorumActor>) (QuorumActor,?>)getQuorum().getActor();
return (QuorumActor>) (QuorumActor) getQuorum()
.getActor();
}
@Override
public boolean isMember() {
final UUID[] a = getQuorum().getMembers();
for(UUID t : a) {
if(serviceId.equals(t))
return true;
}
return false;
}
@Override
public boolean isPipelineMember() {
final UUID[] a = getQuorum().getPipeline();
for(UUID t : a) {
if(serviceId.equals(t))
return true;
}
return false;
}
@Override
public boolean isJoinedMember(final long token) {
final UUID[] a = getQuorum().getJoined();
for(UUID t : a) {
if(serviceId.equals(t)) {
// verify the token is still valid.
return getQuorum().token() == token;
}
}
return false;
}
/**
* @todo This method is a bit odd as it is open to two different semantics
* based on whether or not it will return false or throw a
* {@link QuorumException} if the condition is not true. What makes it
* odd is having the token passed in, but without the token we can not
* know that the test is valid as of the same met quorum.
*
* Right now this is only used by unit tests. Maybe the method should
* go away?
*/
@Override
public boolean isLeader(final long token) {
if (!getServiceId().equals(getQuorum().getLeaderId())) {
// Not the leader.
return false;
}
// Verify quorum is still valid.
getQuorum().assertQuorum(token);
// Ok, we are the leader.
return true;
}
/**
* @todo This method is a bit odd as it is open to two different semantics
* based on whether or not it will return false or throw a
* {@link QuorumException} if the condition is not true. What makes it
* odd is having the token passed in, but without the token we can not
* know that the test is valid as of the same met quorum.
*
* Right now this is only used by unit tests. Maybe the method should
* go away?
*/
@Override
public boolean isFollower(final long token) {
final UUID serviceId = getServiceId();
final UUID[] joined = getQuorum().getJoined();
for (int i = 0; i < joined.length; i++) {
final boolean eq = serviceId.equals(joined[i]);
if (!eq)
continue;
if (i == 0) {
// Not a follower.
return false;
}
// Verify quorum is still valid.
getQuorum().assertQuorum(token);
// Ok, we are a follower.
return true;
}
return false;
}
/**
* @todo This method is a bit odd as it is open to two different semantics
* based on whether or not it will return false or throw a
* {@link QuorumException} if the condition is not true. What makes it
* odd is having the token passed in, but without the token we can not
* know that the test is valid as of the same met quorum.
*
* Right now this is only used by unit tests. Maybe the method should
* go away?
*/
@Override
public boolean isLastInChain(final long token) {
final UUID serviceId = getServiceId();
final UUID[] pipeline = getQuorum().getPipeline();
if (serviceId.equals(pipeline[pipeline.length - 1])) {
// Verify quorum is still valid.
getQuorum().assertQuorum(token);
// Ok, we are at the end of the pipeline.
return true;
}
return false;
}
@Override
public UUID getDownstreamServiceId() {
final UUID serviceId = getServiceId();
final UUID[] pipeline = getQuorum().getPipeline();
for (int i = 0; i < pipeline.length - 1; i++) {
final boolean eq = serviceId.equals(pipeline[i]);
if (!eq)
continue;
// The next service in the pipeline after this service.
final UUID nextId = pipeline[i + 1];
// Ok, we are at the end of the pipeline.
return nextId;
}
// No such service.
return null;
}
protected void assertQuorum(final long token) {
getQuorum().assertQuorum(token);
}
@Override
public void assertLeader(final long token) {
getQuorum().assertLeader(token);
}
protected void assertFollower(final long token) {
final UUID serviceId = getServiceId();
final UUID[] joined = getQuorum().getJoined();
for (int i = 0; i < joined.length; i++) {
final boolean eq = serviceId.equals(joined[i]);
if (!eq)
continue;
if (i == 0) {
// We are the leader (not a follower).
throw new QuorumException();
}
// We are a follower. Now verify quorum is still valid.
getQuorum().assertQuorum(token);
}
// We are not a joined service.
throw new QuorumException();
}
/*
* QuorumStateChangeListener
*/
/**
* This is used to dispatch the {@link QuorumStateChangeListener} events.
*/
private final CopyOnWriteArraySet listeners = new CopyOnWriteArraySet();
/**
* Add a delegate listener.
*
* @param listener
* The listener.
*/
protected void addListener(final QuorumStateChangeListener listener) {
if (listener == null)
throw new IllegalArgumentException();
this.listeners.add(listener);
}
/**
* Remove a delegate listener.
*
* @param listener
* The listener.
*/
protected void removeListener(final QuorumStateChangeListener listener) {
if (listener == null)
throw new IllegalArgumentException();
this.listeners.remove(listener);
}
@Override
public void memberAdd() {
for (QuorumStateChangeListener l : listeners) {
l.memberAdd();
}
}
@Override
public void memberRemove() {
for (QuorumStateChangeListener l : listeners) {
l.memberRemove();
}
}
@Override
public void pipelineAdd() {
for (QuorumStateChangeListener l : listeners) {
l.pipelineAdd();
}
}
@Override
public void pipelineRemove() {
for (QuorumStateChangeListener l : listeners) {
l.pipelineRemove();
}
}
@Override
public void pipelineElectedLeader() {
for (QuorumStateChangeListener l : listeners) {
l.pipelineElectedLeader();
}
}
@Override
public void pipelineChange(final UUID oldDownStreamId, final UUID newDownStreamId) {
for (QuorumStateChangeListener l : listeners) {
l.pipelineChange(oldDownStreamId, newDownStreamId);
}
}
@Override
public void pipelineUpstreamChange() {
for (QuorumStateChangeListener l : listeners) {
l.pipelineUpstreamChange();
}
}
@Override
public void consensus(final long lastCommitTime) {
for (QuorumStateChangeListener l : listeners) {
l.consensus(lastCommitTime);
}
}
@Override
public void lostConsensus() {
for (QuorumStateChangeListener l : listeners) {
l.lostConsensus();
}
}
@Override
public void serviceJoin() {
for (QuorumStateChangeListener l : listeners) {
l.serviceJoin();
}
}
@Override
public void serviceLeave() {
for (QuorumStateChangeListener l : listeners) {
l.serviceLeave();
}
}
@Override
public void quorumBreak() {
for (QuorumStateChangeListener l : listeners) {
l.quorumBreak();
}
}
@Override
public void quorumMeet(final long token, final UUID leaderId) {
for (QuorumStateChangeListener l : listeners) {
l.quorumMeet(token, leaderId);
}
}
}