The parent class of observer and follower when learning defines common properties and methods
Subclasses Follower and Observer
Internal class:
PacketInFlight indicates that there is no commit message in the proposal
static class PacketInFlight { TxnHeader hdr; Record rec; }
Properties:
QuorumPeer |
Server node |
LearnerZooKeeperServer |
Service node of the learner |
BufferedOutputStream |
Output stream |
Socket |
Port socket |
InetSocketAddress |
Address information |
InputArchive |
Input Archive |
OutputArchive |
Output Archive |
leaderProtocolVersion |
leader protocol version |
BUFFERED_MESSAGE_SIZE |
Cache information size |
MessageTracker |
Receive and send messages in sequence |
Method
validateSession(ServerCnxn cnxn, long clientId, int timeout) |
Verify session validity |
writePacket(QuorumPacket pp, boolean flush) |
Send package to leader |
readPacket(QuorumPacket pp) |
Read message from leader |
request(Request request) |
Send request to leader |
findLeader |
Find the address information considered as leader |
createSocket() |
Create socket object |
registerWithLeader(int pktType) |
Execute handshake protocol to establish a follower/observer connection |
Verify session validity to server
void validateSession(ServerCnxn cnxn, long clientId, int timeout) throws IOException { LOG.info("Revalidating client: 0x" + Long.toHexString(clientId)); ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); dos.writeLong(clientId); dos.writeInt(timeout); dos.close(); QuorumPacket qp = new QuorumPacket(Leader.REVALIDATE, -1, baos.toByteArray(), null); pendingRevalidations.put(clientId, cnxn); if (LOG.isTraceEnabled()) { ZooTrace.logTraceMessage( LOG, ZooTrace.SESSION_TRACE_MASK, "To validate session 0x" + Long.toHexString(clientId)); } writePacket(qp, true); } void writePacket(QuorumPacket pp, boolean flush) throws IOException { synchronized (leaderOs) { if (pp != null) { messageTracker.trackSent(pp.getType()); leaderOs.writeRecord(pp, "packet"); } if (flush) { bufferedOutput.flush(); } } } void request(Request request) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream oa = new DataOutputStream(baos); oa.writeLong(request.sessionId); oa.writeInt(request.cxid); oa.writeInt(request.type); if (request.request != null) { request.request.rewind(); int len = request.request.remaining(); byte[] b = new byte[len]; request.request.get(b); request.request.rewind(); oa.write(b); } oa.close(); QuorumPacket qp = new QuorumPacket(Leader.REQUEST, -1, baos.toByteArray(), request.authInfo); writePacket(qp, true); } //Find current leader information protected QuorumServer findLeader() { QuorumServer leaderServer = null; // Find the leader by id Vote current = self.getCurrentVote(); for (QuorumServer s : self.getView().values()) { if (s.id == current.getId()) { // Ensure we have the leader's correct IP address before // attempting to connect. s.recreateSocketAddresses(); leaderServer = s; break; } } if (leaderServer == null) { LOG.warn("Couldn't find the leader with id = " + current.getId()); } return leaderServer; } //connected socket sockConnect(Socket sock, InetSocketAddress addr, int timeout) //Establish a connection with the leader /** * Establish a connection with the LearnerMaster found by findLearnerMaster. * Followers only connect to Leaders, Observers can connect to any active LearnerMaster. * Retries until either initLimit time has elapsed or 5 tries have happened. * @param addr - the address of the Peer to connect to. * @throws IOException - if the socket connection fails on the 5th attempt * if there is an authentication failure while connecting to leader * @throws X509Exception * @throws InterruptedException */ protected void connectToLeader(InetSocketAddress addr, String hostname) throws IOException, InterruptedException, X509Exception { this.sock = createSocket(); this.leaderAddr = addr; // leader connection timeout defaults to tickTime * initLimit int connectTimeout = self.tickTime * self.initLimit; // but if connectToLearnerMasterLimit is specified, use that value to calculate // timeout instead of using the initLimit value if (self.connectToLearnerMasterLimit > 0) { connectTimeout = self.tickTime * self.connectToLearnerMasterLimit; } int remainingTimeout; long startNanoTime = nanoTime(); for (int tries = 0; tries < 5; tries++) { try { // recalculate the init limit time because retries sleep for 1000 milliseconds remainingTimeout = connectTimeout - (int) ((nanoTime() - startNanoTime) / 1000000); if (remainingTimeout <= 0) { LOG.error("connectToLeader exceeded on retries."); throw new IOException("connectToLeader exceeded on retries."); } sockConnect(sock, addr, Math.min(connectTimeout, remainingTimeout)); if (self.isSslQuorum()) { //Start shaking hands ((SSLSocket) sock).startHandshake(); } sock.setTcpNoDelay(nodelay); break; } catch (IOException e) { //Abnormal remainingTimeout = connectTimeout - (int) ((nanoTime() - startNanoTime) / 1000000); //Remaining timeout if (remainingTimeout <= 1000) { //Print error log LOG.error("Unexpected exception, connectToLeader exceeded. tries=" + tries + ", remaining init limit=" + remainingTimeout + ", connecting to " + addr, e); throw e; //More than 4 attempts } else if (tries >= 4) { //Print error log LOG.error("Unexpected exception, retries exceeded. tries=" + tries + ", remaining init limit=" + remainingTimeout + ", connecting to " + addr, e); throw e; } else { //Warn LOG.warn("Unexpected exception, tries=" + tries + ", remaining init limit=" + remainingTimeout + ", connecting to " + addr, e); //Try to establish socket connection again this.sock = createSocket(); } } //Read configuration delay time, default 100ns Thread.sleep(leaderConnectDelayDuringRetryMs); } self.authLearner.authenticate(sock, hostname); leaderIs = BinaryInputArchive.getArchive(new BufferedInputStream(sock.getInputStream())); bufferedOutput = new BufferedOutputStream(sock.getOutputStream()); leaderOs = BinaryOutputArchive.getArchive(bufferedOutput); }