protected abstract class AbstractQuorum.QuorumActorBase extends Object implements QuorumActor<S,C>
QuorumActor
implementations. The methods on this
base class are designed maintain certain invariants in the distributed,
both for this service and (in the case of forcing a pipeline leave on
another service) for other services.
This class does NOT cause changes in the local AbstractQuorum
state directly. Instead, it makes changes to the distributed quorum state
which are perceived by the AbstractQuorum.QuorumWatcherBase
, which makes the
corresponding adjustments to the AbstractQuorum
's internal state.
In order to provide the postcondition guarantee for actions that the
change has been made to the distributed quorum state, the
QuorumActor
awaits an appropriate Condition
on the
AbstractQuorum
and then verifies that the desired state change
has occurred. This mechanism relies on the asynchronous perception of the
change in the distributed quorum state by the paired
AbstractQuorum.QuorumWatcherBase
and its update of the internal state maintained
on the AbstractQuorum
.
Note: It is not possible in a distributed system to guarantee that state changes made by other processes will not conflict with those which are made by this actor on the behalf of its service. However, outside of rare cases such as forcing another service to withdraw from the pipeline, all services act solely on their own facet of the distributed quorum state and all state changes are those which can be made atomic using a suitable distributed state system, such as zookeeper.
Everything is done while holding the AbstractQuorum.lock
. Since
each service only acts on itself, the distributed state should remain
consistent. The AbstractQuorum
and the AbstractQuorum.QuorumActorBase
both rely on the AbstractQuorum
s internal image of the
distributed quorum state, which is maintained by the
AbstractQuorum.QuorumWatcherBase
.
The public API "add" methods follow a pattern which rejects operations if
the preconditions for the action are not met while holding the
AbstractQuorum.lock
. For example, a service can not "join" unless
it is a member, has cast a vote, there is a consensus for that vote, and
the service is part of the pipeline. The detailed preconditions are
documented on the QuorumActor
.
The public API "remove" methods follow a pattern which retracts any other
information which must be retracted as a precondition before the
specified retraction may be applied. These preconditions are evaluated
while holding the AbstractQuorum.lock
. Likewise, the actions are
taken while holding that lock. Since the AbstractQuorum.QuorumWatcherBase
must
obtain the lock in order to update the AbstractQuorum
's internal
state, the internal state of the AbstractQuorum
will not (in
general) update until after the public API method releases the lock (this
might not be true for the within JVM mock objects since the watcher can
run in the same thread as the actor).
For example, the public API member remove operation is implemented as
follows. If, while holding the lock, the service is a member, then the
operation delegates to each of the other public API methods to remove it
from the joined services, the pipeline, and withdraw its votes. Finally,
the public memberRemove()
method invokes the protected method
doMemberRemove()
method to actually remove the service from the
set of member services in the distributed quorum state.
The public API methods all use conditional logic to cut down on remote
operations if the AbstractQuorum
's internal state shows that the
service is not a member, not in the pipeline, has not cast a vote, etc.
Modifier and Type | Class and Description |
---|---|
protected class |
AbstractQuorum.QuorumActorBase.ActorTask
Task used to run an action.
|
Modifier and Type | Field and Description |
---|---|
protected String |
logicalServiceId |
protected UUID |
serviceId |
Modifier | Constructor and Description |
---|---|
protected |
AbstractQuorum.QuorumActorBase(String logicalServiceId,
UUID serviceId) |
Modifier and Type | Method and Description |
---|---|
void |
castVote(long lastCommitTime)
Cast a vote on the behalf of the associated service.
|
void |
clearToken()
Clear the quorum token.
|
protected abstract void |
doCastVote(long lastCommitTime) |
protected abstract void |
doClearToken() |
protected abstract void |
doMemberAdd() |
protected void |
doMemberRemove() |
protected abstract void |
doMemberRemove(UUID serviceId) |
protected abstract void |
doPipelineAdd() |
protected void |
doPipelineRemove() |
protected abstract void |
doPipelineRemove(UUID serviceId) |
protected abstract void |
doServiceJoin() |
protected void |
doServiceLeave() |
protected abstract void |
doServiceLeave(UUID serviceId) |
protected abstract void |
doSetToken(long newToken) |
protected void |
doWithdrawVote() |
protected abstract void |
doWithdrawVote(UUID serviceId) |
void |
forceRemoveService(UUID psid)
Remove the service from the quorum.
|
QuorumMember<S> |
getQuorumMember()
The service on whose behalf this class is acting.
|
Quorum<S,C> |
getQuourm()
The
Quorum . |
UUID |
getServiceId()
The
UUID of the service on whose behalf this class is acting. |
void |
memberAdd()
Add the service to the set of quorum members.
|
void |
memberRemove()
Remove the service from the set of quorum members.
|
void |
pipelineAdd()
Add the service to the write pipeline.
|
void |
pipelineRemove()
Remove the service from the write pipeline.
|
protected boolean |
reorganizePipeline()
Invoked when our client will become the leader to (a) reorganize the
write pipeline such that our client is the first service in the write
pipeline (the leader MUST be the first service in the write
pipeline); and (b) to optionally optimize the write pipeline
for the network topology.
|
void |
serviceJoin()
Add the associated service to the set of joined services for the quorum.
|
void |
serviceLeave()
Remove the associated service from the set of joined services for the
quorum.
|
void |
setToken(long newToken)
Atomically set the lastValidToken and the current token on the quorum
equal to the given token.
|
void |
withdrawVote()
Withdraw the vote cast by the service (a service has only one vote).
|
protected final String logicalServiceId
protected final UUID serviceId
public final QuorumMember<S> getQuorumMember()
QuorumActor
getQuorumMember
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
public final Quorum<S,C> getQuourm()
QuorumActor
Quorum
.getQuourm
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
public final UUID getServiceId()
QuorumActor
UUID
of the service on whose behalf this class is acting.getServiceId
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
public final void memberAdd()
QuorumActor
memberAdd
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
public final void castVote(long lastCommitTime)
QuorumActor
When a service needs to re-synchronize with a quorum, it initially votes its current lastCommitTime. Once the service is receiving writes from the write pipeline and has synchronized any historical delta, it will update its vote and join the quorum at the next commit point (or immediately if there are no outstanding writes against the quorum).
castVote
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
lastCommitTime
- The lastCommitTime timestamp for which the service casts its
vote.public final void pipelineAdd()
QuorumActor
pipelineAdd
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
public final void serviceJoin()
QuorumActor
serviceJoin
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
public final void setToken(long newToken)
QuorumActor
newToken := lastValidToken + 1
.setToken
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
public final void clearToken()
QuorumActor
clearToken
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
public final void memberRemove()
QuorumActor
memberRemove
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
public final void withdrawVote()
QuorumActor
withdrawVote
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
public final void pipelineRemove()
QuorumActor
pipelineRemove
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
public final void serviceLeave()
QuorumActor
serviceLeave
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
protected abstract void doMemberAdd()
protected final void doMemberRemove()
protected abstract void doMemberRemove(UUID serviceId)
protected abstract void doCastVote(long lastCommitTime)
protected final void doWithdrawVote()
protected abstract void doWithdrawVote(UUID serviceId)
protected abstract void doPipelineAdd()
protected final void doPipelineRemove()
protected abstract void doPipelineRemove(UUID serviceId)
protected abstract void doServiceJoin()
protected final void doServiceLeave()
protected abstract void doServiceLeave(UUID serviceId)
protected abstract void doSetToken(long newToken)
protected abstract void doClearToken()
public final void forceRemoveService(UUID psid)
Note: This implements an unconditional remove of the specified service. It is intended to force a different service out of the pipeline. This code deliberately takes this action unconditionally and does NOT await the requested state change.
Note: This code could potentially cause the remote service to deadlock in one of the conditionalXXX() methods if it is concurrently attempting to execute quorum action on itself. If this problem is observed, we should add a timeout to the conditionalXXX() methods that will force them to fail rather than block forever. This will then force the service into an error state if its QuorumActor can not carry out the requested action within a specified timeout.
forceRemoveService
in interface QuorumActor<S extends Remote,C extends QuorumClient<S>>
psid
- The UUID of the service to be removed.protected boolean reorganizePipeline()
The default implementation directs each service before this service in the write pipeline to move itself to the end of the write pipeline.
true
if the pipeline order was modified.HAPipelineGlue.moveToEndOfPipeline()
Copyright © 2006–2019 SYSTAP, LLC DBA Blazegraph. All rights reserved.