S
- public abstract class QuorumPipelineImpl<S extends HAPipelineGlue> extends Object implements QuorumPipeline<S>, QuorumStateChangeListener
QuorumPipeline
implementation.
The QuorumMember
must pass along the "pipeline" messages, including:
QuorumStateChangeListener.pipelineAdd()
QuorumStateChangeListener.pipelineRemove()
QuorumStateChangeListener.pipelineChange(UUID, UUID)
Since the write pipeline is used to synchronize services trying to join the
quorum as well as the replicate writes for services joined with the quorum,
HAReceiveService
may be live for a met quorum even though the
QuorumMember
on whose behalf this class is acting is not joined with
the met quorum.
pipelineElectedLeader()
event. A follower leave only causes the
follower to leave the pipeline and results in a
pipelineChange(UUID, UUID)
event.
There are two cases for a follower leave: (A) when the follower did not did not have a downstream node; and (B) when there is downstream node. For (B), the upstream node from the left follower should reconfigure for the new downstream node and retransmit the current cache block and the event should be otherwise unnoticed.
Handling a follower join requires us to synchronize the follower first which requires some more infrastructure and should be done as part of the HA synchronization test suite.
What follows is an example of how events will arrive for a quorum of three services: A, B, and C.
A.getActor().pipelineAdd() => A.pipelineAdd() B.getActor().pipelineAdd() => B.pipelineAdd(); A.pipelineChange(null,B); C.getActor().pipelineAdd() => C.pipelineAdd(); B.pipelineChange(null,C);At this point the pipeline order is
[A,B,C]
. Notice that the
HASendService
for A is not established until the
A.pipelineChange(null,B)
sets B as the new downstream service
for A. Likewise, B will not relay to C until it handles the
B.pipelineChange(null,C)
event.
Given the pipeline order [A,B,C]
, if B were to leave, then the
events would be:
B.getActor().pipelineRemove() => B.pipelineRemove(); A.pipelineChange(B,C);and when this class handles the
A.pipelineChange(B,C)
event, it
must update the HAReceiveService
such that it now relays data to C.
On the other hand, given the pipeline order [A,B,C]
, if C were
to leave the events would be:
C.getActor().pipelineRemove() => C.pipelineRemove(); B.pipelineChange(C,null);and when this class handles the
B.pipelineChange(C,null)
event,
it must update the C's HAReceiveService
such that it continues to
receive data, but no longer relays data to a downstream service.Constructor and Description |
---|
QuorumPipelineImpl(QuorumMember<S> member) |
Modifier and Type | Method and Description |
---|---|
void |
consensus(long lastCommitTime)
Invoked when a consensus has been achieved among
(k+1)/2
services concerning a shared lastCommitTime (really, this is not a
consensus but a simple majority). |
protected void |
finalize()
Extended to invoke
#tearDown() in order to guarantee the eventual
release of the receiveBuffer and the shutdown of the
sendService or receiveService . |
protected long |
getRetrySendTimeoutNanos()
Once this timeout is elapsed, retrySend() will fail.
|
protected abstract void |
handleReplicatedWrite(IHASyncRequest req,
IHAWriteMessage msg,
ByteBuffer data)
Core implementation handles the message and payload when received on a
service.
|
protected abstract void |
incReceive(IHASyncRequest req,
IHAWriteMessage msg,
int nreads,
int rdlen,
int rem)
Notify that some payload bytes have been incrementally received for an
IHAMessage . |
void |
lostConsensus()
Invoked when the consensus is lost.
|
void |
memberAdd()
Invoked when this service is added as a quorum member.
|
void |
memberRemove()
Invoked when this service is removed as a quorum member.
|
void |
pipelineAdd()
Invoked when this service is added to the write pipeline.
|
void |
pipelineChange(UUID oldDownStreamId,
UUID newDownStreamId)
Invoked for this service when the downstream service in the write
pipeline has changed.
|
void |
pipelineElectedLeader()
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 |
pipelineRemove()
Invoked when this service is removed from the write pipeline.
|
void |
pipelineUpstreamChange()
Invoked for this service when the upstream service in the write pipeline
has been removed.
|
void |
processEvents()
Called from ErrorTask in HAJournalServer to ensure that events are
processed before entering SeekConsensus.
|
void |
quorumBreak()
Invoked when a quorum breaks.
|
void |
quorumMeet(long token,
UUID leaderId)
Invoked when a quorum meets.
|
Future<Void> |
receiveAndReplicate(IHASyncRequest req,
IHASendState snd,
IHAWriteMessage msg)
Return a
Future for a task which will replicate an NIO buffer
along the write pipeline. |
Future<Void> |
replicate(IHASyncRequest req,
IHAWriteMessage msg,
ByteBuffer b)
Return a
Future for a task which will replicate an NIO buffer
along the write pipeline. |
Future<IHAPipelineResetResponse> |
resetPipeline(IHAPipelineResetRequest req)
Reset the pipeline (blocking).
|
void |
serviceJoin()
Invoked when this service joins the quorum.
|
void |
serviceLeave()
Invoked when this service leaves the quorum.
|
clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
getLastCommitCounter, getLastCommitTime, getStoreUUID, logRootBlock, logWriteCacheBlock, purgeHALogs
public QuorumPipelineImpl(QuorumMember<S> member)
protected long getRetrySendTimeoutNanos()
Note: This gets overridden in the ZK aware version and set to a constant greater than the then-current negotiated timeout for the client.
protected void finalize() throws Throwable
#tearDown()
in order to guarantee the eventual
release of the receiveBuffer
and the shutdown of the
sendService
or receiveService
.public void pipelineAdd()
QuorumStateChangeListener
pipelineAdd
in interface QuorumStateChangeListener
public void pipelineElectedLeader()
QuorumStateChangeListener
pipelineElectedLeader
in interface QuorumStateChangeListener
public void pipelineRemove()
QuorumStateChangeListener
pipelineRemove
in interface QuorumStateChangeListener
public void pipelineChange(UUID oldDownStreamId, UUID newDownStreamId)
QuorumStateChangeListener
pipelineChange
in interface QuorumStateChangeListener
public void pipelineUpstreamChange()
QuorumStateChangeListener
pipelineUpstreamChange
in interface QuorumStateChangeListener
public void memberAdd()
QuorumStateChangeListener
memberAdd
in interface QuorumStateChangeListener
public void memberRemove()
QuorumStateChangeListener
memberRemove
in interface QuorumStateChangeListener
public void consensus(long lastCommitTime)
QuorumStateChangeListener
(k+1)/2
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.
Once a consensus has been reached, each QuorumMember
which agrees
on that lastCommitTime MUST do a QuorumStateChangeListener.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.
consensus
in interface QuorumStateChangeListener
lastCommitTime
- The last commit time around which a consensus was established.QuorumStateChangeListener.serviceJoin()
,
#electedLeader(long)
,
#electedFollower(long)
,
QuorumStateChangeListener.lostConsensus()
public void lostConsensus()
QuorumStateChangeListener
lostConsensus
in interface QuorumStateChangeListener
QuorumStateChangeListener.consensus(long)
public void serviceJoin()
QuorumStateChangeListener
serviceJoin
in interface QuorumStateChangeListener
public void serviceLeave()
QuorumStateChangeListener
serviceLeave
in interface QuorumStateChangeListener
public void quorumMeet(long token, UUID leaderId)
QuorumStateChangeListener
#isLeader(long)
, joined as a
follower (using #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).
The following pre-conditions will be satisfied before this message is
sent to the QuorumMember
:
(k+1)/2
services which have voted
for the same lastCommitTime.(k+1)/2
services joined with the
quorum. The join order
will be the same
as the Quorum.getVotes()
for the services which voted for the
lastCommitTimeQuorumStateChangeListener.memberAdd()
, QuorumStateChangeListener.pipelineAdd()
,
QuorumStateChangeListener.consensus(long)
, and QuorumStateChangeListener.serviceJoin()
events.When control returns from this method, the following post-conditions should be true:
QuorumMember
is joined with the quorum but it can not
satisfy these post-conditions, then it must
leave
the Quorum
.quorumMeet
in interface QuorumStateChangeListener
token
- The newly assigned quorum token.leaderId
- The 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 #getLeader(long)
at any time for a met quorum.)public void quorumBreak()
QuorumStateChangeListener
quorumBreak
in interface QuorumStateChangeListener
public Future<IHAPipelineResetResponse> resetPipeline(IHAPipelineResetRequest req) throws IOException
QuorumPipeline
HAReceiveService
(including the inner HASendService
). The
next message and payload relayed from the leader will cause new socket
connections to be established.resetPipeline
in interface QuorumPipeline<S extends HAPipelineGlue>
Future
for the operation on the local service.IOException
public Future<Void> replicate(IHASyncRequest req, IHAWriteMessage msg, ByteBuffer b) throws IOException
QuorumPipeline
Future
for a task which will replicate an NIO buffer
along the write pipeline. This method is only invoked by the quorum
leader. The payload is replicated to the first follower in the write
pipeline. That follower will accept the payload (and replicate it if
necessary) using #receiveAndReplicate(IHAWriteMessage)
.
Note: The implementation of this method should be robust to changes in
the write pipeline. Specifically, if a follower leaves the write
pipeline, it should attempt to retransmit the message and the payload
while allowing time for the write pipeline to be reconfigured in response
to the related QuorumMember
events.
replicate
in interface QuorumPipeline<S extends HAPipelineGlue>
req
- A synchronization request (optional). This is only non-null
when historical WriteCache
blocks are being replayed
down the write pipeline in order to synchronize a service.msg
- The RMI metadata about the payload.b
- The payload. The bytes from the position to the limit will be
transmitted (note that the #of bytes remaining in the buffer
MUST agree with IHAWriteMessageBase.getSize()
).IOException
public Future<Void> receiveAndReplicate(IHASyncRequest req, IHASendState snd, IHAWriteMessage msg) throws IOException
QuorumPipeline
Future
for a task which will replicate an NIO buffer
along the write pipeline. This method is invoked for any node except the
master, including the last node in the failover chain.receiveAndReplicate
in interface QuorumPipeline<S extends HAPipelineGlue>
req
- A synchronization request (optional). This is only non-null
when historical WriteCache
blocks are being replayed
down the write pipeline in order to synchronize a service.snd
- Metadata about the state of the sender and potentially the
routing of the payload along the write replication pipeline.msg
- The RMI metadata about the payload.IOException
protected abstract void handleReplicatedWrite(IHASyncRequest req, IHAWriteMessage msg, ByteBuffer data) throws Exception
Note: Replication of the message and payload is handled by the caller. The implementation of this method is NOT responsible for replication.
req
- The synchronization request (optional). When non-
null
the msg and payload are historical data.
When null
they are live data.msg
- Metadata about a buffer containing data replicated to this
node.data
- The buffer containing the data.Exception
protected abstract void incReceive(IHASyncRequest req, IHAWriteMessage msg, int nreads, int rdlen, int rem) throws Exception
IHAMessage
.msg
- The message.nreads
- The number of reads performed against the upstream socket for
this message.rdlen
- The number of bytes read from the socket in this read.rem
- The number of bytes remaining before the payload has been
fully read.Exception
public void processEvents()
Copyright © 2006–2019 SYSTAP, LLC DBA Blazegraph. All rights reserved.