public abstract class AbstractQuorum<S extends Remote,C extends QuorumClient<S>> extends Object implements Quorum<S,C>
Modifier and Type | Class and Description |
---|---|
protected static class |
AbstractQuorum.E
Simple event impl.
|
protected class |
AbstractQuorum.QuorumActorBase
Base class for
QuorumActor implementations. |
protected class |
AbstractQuorum.QuorumWatcherBase
Base class for
QuorumWatcher implementations. |
Modifier and Type | Field and Description |
---|---|
protected static String |
ERR_BAD_TOKEN
Text when an operation is not permitted because the new value for the
lastValidToken is not strictly greater than the current value.
|
protected static String |
ERR_CAN_NOT_MEET
Text when an operation is not permitted because the quorum can not meet.
|
protected static String |
ERR_NOT_IN_CONSENSUS
Text when an operation is not permitted because the service has not cast
its vote for a lastCommitTime around which there is a consensus of
(k+1)/2 quorum members.
|
protected static String |
ERR_NOT_MEMBER
Text when an operation is not permitted because the service is not a
quorum member.
|
protected static String |
ERR_NOT_PIPELINE
Text when an operation is not permitted because the service is not part
of the write pipeline.
|
protected static String |
ERR_QUORUM_BREAK
Message when a quorum breaks..
|
protected static String |
ERR_QUORUM_MET
Text when an operation is not permitted while the quorum is met.
|
protected int |
kmeet
The minimum #of joined services that constitutes a quorum as defined by
(k + 1) / 2 . |
protected ReentrantLock |
lock
The lock protecting state changes in the remaining fields and used to
provide
Condition s used to await various states. |
protected static org.apache.log4j.Logger |
log |
protected static org.apache.log4j.Logger |
qlog
Dedicated logger for quorum state.
|
Modifier | Constructor and Description |
---|---|
protected |
AbstractQuorum(int k)
Constructor, which MUST be followed by
#start() to begin
operations. |
Modifier and Type | Method and Description |
---|---|
void |
addListener(QuorumListener listener)
Add a listener
|
void |
assertLeader(long token)
Assert that the token is still valid and that the
Quorum.getClient() is
the quorum leader. |
void |
assertQuorum(long token)
Assert that the quorum associated with the token is still valid.
|
void |
awaitBreak()
Await a met break (blocking).
|
void |
awaitBreak(long timeout,
TimeUnit units)
Await a met break (blocking).
|
long |
awaitQuorum()
Await a met quorum (blocking).
|
long |
awaitQuorum(long timeout,
TimeUnit units)
Await a met quorum (blocking).
|
protected void |
finalize() |
QuorumActor<S,C> |
getActor()
The object used to effect changes in distributed quorum state on the
behalf of the
QuorumMember . |
Long |
getCastVote(UUID serviceId)
Return the vote cast by the service.
|
Long |
getCastVoteIfConsensus(UUID serviceId)
Search for the vote for the service.
|
C |
getClient()
Return the
QuorumClient iff the quorum is running. |
protected C |
getClientNoLock() |
UUID[] |
getJoined()
Return the identifiers for the member services joined with this quorum.
|
UUID |
getLastInPipeline()
Return the
UUID of the service which is the last service in the
write pipeline. |
protected long |
getLastValidTokenFromQuorumState(C client)
Initialization method must return the lastValidToken from the durable
quorum state and
Quorum.NO_QUORUM if there is no durable state. |
UUID |
getLeaderId()
|
QuorumMember<S> |
getMember()
Return the
QuorumMember iff the quorum is running. |
UUID[] |
getMembers()
Return the identifiers for the member services (all known physical
services for the logical service).
|
UUID[] |
getPipeline()
Return the service identifiers for the services in the write pipeline in
the order in which they will accept and relay writes.
|
UUID[] |
getPipelinePriorAndNext(UUID serviceId)
Return the
UUID of the service in the pipeline which is
immediately upstream from (prior to) and downstream from (next to) the
specified service. |
Map<Long,UUID[]> |
getVotes()
Return an immutable snapshot of the votes cast by the quorum members.
|
protected QuorumWatcher<S,C> |
getWatcher()
The
QuorumWatcher which informs this AbstactQuorum of
changes occurring in the distributed state of the quorum. |
protected void |
guard(ThreadGuard.Guard r)
Execute a critical region which needs to be interrupted if we have to
terminate the quorum.
|
void |
interruptAll()
Ensure that any guarded regions are interrupted.
|
boolean |
isHighlyAvailable()
Return
true if Quorum.replicationFactor() is GT ONE (1). |
boolean |
isQuorum(int njoined)
Return
true iff the argument is large enough to constitute a
quorum. |
boolean |
isQuorumFullyMet(long token)
Return true iff the #of services joined with the quorum EQUALS
k AND the provided quorum token is valid. |
boolean |
isQuorumMet()
Return true iff the #of services joined with the quorum is GTE
(k + 1)/2 . |
long |
lastValidToken()
The quorum token which was assigned the last time a leader was elected.
|
protected void |
launderThrowable(Throwable t)
Launder something thrown by the
QuorumClient . |
protected abstract AbstractQuorum.QuorumActorBase |
newActor(String logicalServiceId,
UUID serviceId)
|
protected abstract AbstractQuorum.QuorumWatcherBase |
newWatcher(String logicalServiceId)
Factory method invoked by
start(QuorumClient) . |
void |
removeListener(QuorumListener listener)
Remove a listener (the quorum's client is always a listener).
|
int |
replicationFactor()
Return k, the target replication factor.
|
protected void |
sendEvent(QuorumEvent e)
Send the listener an informative event outside of the thread in which we
actually process these events.
|
void |
start(C client)
Begin asynchronous processing.
|
void |
terminate()
Terminate any asynchronous processing associated with maintaining the
Quorum state. |
long |
token()
The current token for the quorum.
|
String |
toString()
Return a human readable representation of the local copy of the
distributed quorum state (non-blocking).
|
String |
toStringAtomic()
Return a human readable representation of an atomic snapshot of the local
copy of the distributed quorum state.
|
protected static final transient org.apache.log4j.Logger log
protected static final transient org.apache.log4j.Logger qlog
protected static final transient String ERR_NOT_MEMBER
protected static final transient String ERR_NOT_PIPELINE
protected static final transient String ERR_NOT_IN_CONSENSUS
protected static final transient String ERR_BAD_TOKEN
protected static final transient String ERR_QUORUM_MET
protected static final transient String ERR_CAN_NOT_MEET
protected static final transient String ERR_QUORUM_BREAK
protected final int kmeet
(k + 1) / 2
.
Note: This constant is isolated here so we can have "quorums" that
require ALL services to be joined. For example, a highly available system
that can replicate writes but can not resynchronize services that were
not present during a quorum commit would specify the same value for
k
and kmeet
in order to ensure that all services are
joined before the quorum "meets".
TODO Specify means to compute this. It is fixed by the constructor right
now. Maybe we should just pull out an interface for this?
protected final ReentrantLock lock
Condition
s used to await various states. This is exposed
to concrete implementations of the AbstractQuorum.QuorumWatcherBase
.protected AbstractQuorum(int k)
#start()
to begin
operations.protected void guard(ThreadGuard.Guard r) throws InterruptedException
r
- The lambda.InterruptedException
protected void finalize() throws Throwable
public void start(C client)
QuorumListener
, the QuorumActor
and QuorumWatcher
are created, and asynchronous discovery is
initialized for the QuorumWatcher
.protected long getLastValidTokenFromQuorumState(C client)
Quorum.NO_QUORUM
if there is no durable state.public void interruptAll()
public void terminate()
Quorum
Quorum
state.protected abstract AbstractQuorum.QuorumActorBase newActor(String logicalServiceId, UUID serviceId)
logicalServiceId
- The identifier of the logical service corresponding to the
highly available quorum.serviceId
- The UUID
of the service on whose behalf the actor will
act.QuorumActor
which will effect changes in the
distributed state of the quorum.protected abstract AbstractQuorum.QuorumWatcherBase newWatcher(String logicalServiceId)
start(QuorumClient)
.
Note: Additional information can be passed to the watcher factor by
derived classes. For example, the UUID
of the logical service to
logicalServiceId
- The identifier of the logical service whose quorum state
will be watched.QuorumWatcher
which will inform this
AbstactQuorum
of changes occurring in the distributed
state of the quorum.public String toString()
public String toStringAtomic()
public C getClient()
Quorum
QuorumClient
iff the quorum is running.getClient
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
QuorumClient
.protected C getClientNoLock()
public QuorumMember<S> getMember()
Quorum
QuorumMember
iff the quorum is running.getMember
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
QuorumMember
.public QuorumActor<S,C> getActor()
QuorumMember
.getActor
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
QuorumActor
which will effect changes in the
distributed state of the quorum -or- null
if the
client is not a QuorumMember
(only quorum members can
take actions which effect the distributed quorum state).IllegalStateException
- if the quorum is not running.protected QuorumWatcher<S,C> getWatcher()
QuorumWatcher
which informs this AbstactQuorum
of
changes occurring in the distributed state of the quorum.IllegalStateException
- if the quorum is not running.public final void addListener(QuorumListener listener)
Quorum
addListener
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
listener
- The listener.public final void removeListener(QuorumListener listener)
Quorum
removeListener
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
listener
- The listener.public final int replicationFactor()
Quorum
A normal quorum requires a simple majority and a replication factor that
is a non-negative odd integer (1, 3, 5, 7, etc). For this case, a quorum
exists only when (k + 1)/2
physical services for the same
logical service have an agreement on state. A single service with
k := 1
is the degenerate case and has a minimum quorum size
of ONE (1). High availability is only possible when k
is GT
ONE (1). Thus k := 3
is the minimum value for which services
can be highly available and has a minimum quorum size of 2
.
replicationFactor
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
Quorum.isQuorum(int)
public final boolean isQuorum(int njoined)
Quorum
true
iff the argument is large enough to constitute a
quorum.
Note: This method makes it easier to write code that obeys policies other than simple majority rule. For example, a quorum could exist only when ALL services are joined. This alternative rule is useful when the services do not support a resynchronization policy. For such services, all services must participate in all commits since services can not recover if they miss a commit. Simple replication is an example of this policy.
public final boolean isHighlyAvailable()
Quorum
true
if Quorum.replicationFactor()
is GT ONE (1).
High availability exists (in principle) when the
Quorum.replicationFactor()
k is greater than one. High
availability exists (in practice) when the Quorum
is met
for a Quorum
that is
configured for high availability.isHighlyAvailable
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
true
if this Quorum
is highly available
in principlepublic final long lastValidToken()
Quorum
lastValidToken
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
public final UUID[] getMembers()
Quorum
getMembers
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
UUID
s of the member services.public final Map<Long,UUID[]> getVotes()
Quorum
public final Long getCastVote(UUID serviceId)
Quorum
getCastVote
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
serviceId
- The service.null
if the
service has not cast a vote.public Long getCastVoteIfConsensus(UUID serviceId)
Quorum
getCastVoteIfConsensus
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
serviceId
- The service identifier.null
if the service is not participating in a
consensus.public final UUID[] getJoined()
Quorum
public final UUID[] getPipeline()
Quorum
getPipeline
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
UUID
s of the ordered services in the write pipeline.public final UUID getLastInPipeline()
Quorum
UUID
of the service which is the last service in the
write pipeline.getLastInPipeline
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
UUID
of the last service in the write pipeline or
null
if there are no services in the write pipeline.public final UUID[] getPipelinePriorAndNext(UUID serviceId)
Quorum
UUID
of the service in the pipeline which is
immediately upstream from (prior to) and downstream from (next to) the
specified service. These are, respectively, the service from which it
receives data (upstream) and to which it sends data (downstream).getPipelinePriorAndNext
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
serviceId
- The service id.null
if the serviceId does not appear
in the write pipeline -or- an array of two elements whose values
are: [0] The upstream serviceId in the write pipeline, which will
be null
iff serviceId is the first service in
the write pipeline; and [1] The downstream service in the write
pipeline, which will be null
iff serviceId is
the last service in the write pipeline.public final UUID getLeaderId()
Quorum
getLeaderId
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
UUID
of the leader Quorum
leader -or-
null
if the quorum is not met.public final long token()
Quorum
Quorum.NO_QUORUM
. When a leader is elected, it sets the current
token as token := lastValidToken() + 1
. The current token is
cleared to Quorum.NO_QUORUM
if the leader leaves the met quorum. It is
cleared Quorum.NO_QUORUM
if the quorum breaks. While a leader may be
elected many times for the same lastCommitTime, a new quorum
token is assigned each time a leader is elected.public final void assertQuorum(long token)
Quorum
Quorum.token()
somewhere.
This method may then be invoked to verify that the saved token is still
valid and, hence, that the quorum is still met.assertQuorum
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
token
- The token for the quorum.public final void assertLeader(long token)
Quorum
Quorum.getClient()
is
the quorum leader.assertLeader
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
token
- A quorum token.public final boolean isQuorumMet()
Quorum
(k + 1)/2
. A service with a met quorum is highly available
in practice.isQuorumMet
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
public final boolean isQuorumFullyMet(long token)
Quorum
k
AND the provided quorum token is valid. A service with a
fully met quorum may be eligible to release storage associated with
historical allocations since it does not need to maintain history in
support of resynchronization of disconnected quorum services.isQuorumFullyMet
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
token
- The quorum token.public final long awaitQuorum() throws InterruptedException, AsynchronousQuorumCloseException
Quorum
is not met, then this
will block until the Quorum
meets.
This watches the current token and will return as soon as the token is valid.
awaitQuorum
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
AsynchronousQuorumCloseException
- if Quorum.terminate()
is invoked while awaiting a quorum
meet.InterruptedException
public final long awaitQuorum(long timeout, TimeUnit units) throws InterruptedException, TimeoutException, AsynchronousQuorumCloseException
Quorum
Quorum
is not met, then this
will block until the Quorum
meets.awaitQuorum
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
timeout
- The timeout.units
- The timeout units.TimeoutException
- if the timeout expired before the quorum met.AsynchronousQuorumCloseException
- if Quorum.terminate()
is invoked while awaiting a quorum
meet.InterruptedException
public final void awaitBreak() throws InterruptedException, AsynchronousQuorumCloseException
Quorum
awaitBreak
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
AsynchronousQuorumCloseException
- if Quorum.terminate()
is invoked while awaiting a quorum
break.InterruptedException
public final void awaitBreak(long timeout, TimeUnit units) throws InterruptedException, TimeoutException, AsynchronousQuorumCloseException
Quorum
awaitBreak
in interface Quorum<S extends Remote,C extends QuorumClient<S>>
timeout
- The timeout.units
- The timeout units.TimeoutException
- if the timeout expired before the quorum breaks.AsynchronousQuorumCloseException
- if Quorum.terminate()
is invoked while awaiting a quorum
break.InterruptedException
protected void sendEvent(QuorumEvent e)
QuorumListener
. The inner Runnable
will block
waiting for the lock
before it sends the event, so clients will
not see events propagated unless they have been handled by this class
first.e
- The event.protected void launderThrowable(Throwable t)
QuorumClient
.t
- The throwable.Copyright © 2006–2019 SYSTAP, LLC DBA Blazegraph. All rights reserved.