选举完毕之后的数据同步.

在LearnerHandler.run()和Follower.followLeader()方法中存在顺序性的交互操作.那么Leader.lead()只是根据上述2个方法的交互作为状态判断(有同步的过程).
这是一个可读性比较差的实现. 状态完全依赖于顺序性交互顺序.

先画时序交互+流程逻辑图. 


先跑下单测
LearnerTest.syncTest
Zab1_0Test.testNormalObserverRun() 这个也只是启动和同步过程. 涉及到了infom proposal commit ,
对照代码进行注释. 后续加上.
 protected void syncWithLeader(long newLeaderZxid) throws IOException, InterruptedException{

LinkedList<Long> packetsCommitted = new LinkedList<Long>();

LinkedList<PacketInFlight> packetsNotCommitted = new LinkedList<PacketInFlight>();
}
这两个临时变量承载了flower未启动是的proposal和commit指令传送过来的数据.
如果是FollowerZooKeeperServer最终会转存到FollowerZooKeeperServer.pendingTxns,
同时需要syncProcessor.processRequest(request);不同的角色落盘后的操作是不同的.

SyncRequestProcessor的作用. sync数据到磁盘,并且发送ack消息给Leader(通过后续的AckRequestProcessor操作,Observer不发送,注释中有说明).
Zab1_0Test.testNormalObserverRun()
解析:
1.该单测启动了一个Observer
2.模拟了一个LEADER,手动操作Leader的ia和oa发送,接受数据.
ObserverConversation 取名为观察者交互,注意就是为了测试Observer用的. 主要是 提供了Leader的ia和oa,操作这两个和观察者交互.

 仅仅在同步方法的死循环中接受命令和操作. 并没有在后续的正常工作后的监听后接受到任何数据.
在数据同步结束前Leader.UPTODATE,还发送了一个proposal,commit和infom指令.这些都是再observer的同步代码中接受.
之后就没有再发送过消息了.






@Test
public void testNormalObserverRun() throws Exception {
    testObserverConversation(new ObserverConversation() {
        @Override
        public void converseWithObserver(InputArchive ia, OutputArchive oa,
                Observer o) throws Exception {
            File tmpDir = File.createTempFile("test", "dir", testData);
            tmpDir.delete();
            tmpDir.mkdir();
            File logDir = o.zk.getTxnLogFactory().getDataDir().getParentFile();
            File snapDir = o.zk.getTxnLogFactory().getSnapDir().getParentFile();
            try {
                Assert.assertEquals(0, o.self.getAcceptedEpoch());
                Assert.assertEquals(0, o.self.getCurrentEpoch());

                // Setup a database with a single /foo node
                ZKDatabase zkDb = new ZKDatabase(new FileTxnSnapLog(tmpDir, tmpDir));
                final long foo1Zxid = ZxidUtils.makeZxid(1, 1);
                final long foo2Zxid = ZxidUtils.makeZxid(1, 2);
                zkDb.processTxn(new TxnHeader(13, 1313, foo1Zxid, 33,
                        ZooDefs.OpCode.create), new CreateTxn("/foo1",
                        "data1".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
                        false, 1));
                zkDb.processTxn(new TxnHeader(13, 1313, foo2Zxid, 33,
                        ZooDefs.OpCode.create), new CreateTxn("/foo2",
                        "data1".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
                        false, 1));
                Stat stat = new Stat();
                Assert.assertEquals("data1",
                        new String(zkDb.getData("/foo1", stat, null)));
                Assert.assertEquals("data1",
                        new String(zkDb.getData("/foo2", stat, null)));

                QuorumPacket qp = new QuorumPacket();
                readPacketSkippingPing(ia, qp);
                Assert.assertEquals(Leader.OBSERVERINFO, qp.getType());
                Assert.assertEquals(qp.getZxid(), 0);
                LearnerInfo learnInfo = new LearnerInfo();
                ByteBufferInputStream.byteBuffer2Record(
                        ByteBuffer.wrap(qp.getData()), learnInfo);
                Assert.assertEquals(learnInfo.getProtocolVersion(), 0x10000);
                Assert.assertEquals(learnInfo.getServerid(), 0);

                // We are simulating an established leader, so the epoch is 1
                qp.setType(Leader.LEADERINFO);
                qp.setZxid(ZxidUtils.makeZxid(1, 0));
                byte protoBytes[] = new byte[4];
                ByteBuffer.wrap(protoBytes).putInt(0x10000);
                qp.setData(protoBytes);
                oa.writeRecord(qp, null);

                readPacketSkippingPing(ia, qp);
                Assert.assertEquals(Leader.ACKEPOCH, qp.getType());
                Assert.assertEquals(0, qp.getZxid());
                Assert.assertEquals(ZxidUtils.makeZxid(0, 0), ByteBuffer
                        .wrap(qp.getData()).getInt());
                Assert.assertEquals(1, o.self.getAcceptedEpoch());
                Assert.assertEquals(0, o.self.getCurrentEpoch());

                // Send the snapshot we created earlier
                qp.setType(Leader.SNAP);
                qp.setData(new byte[0]);
                qp.setZxid(zkDb.getDataTreeLastProcessedZxid());
                oa.writeRecord(qp, null);
                zkDb.serializeSnapshot(oa);
                oa.writeString("BenWasHere", null);
                qp.setType(Leader.NEWLEADER);
                qp.setZxid(ZxidUtils.makeZxid(1, 0));
                oa.writeRecord(qp, null);

                // Get the ack of the new leader
                readPacketSkippingPing(ia, qp);
                Assert.assertEquals(Leader.ACK, qp.getType());
                Assert.assertEquals(ZxidUtils.makeZxid(1, 0), qp.getZxid());
                Assert.assertEquals(1, o.self.getAcceptedEpoch());
                Assert.assertEquals(1, o.self.getCurrentEpoch());

                Assert.assertEquals(foo2Zxid, o.zk.getLastProcessedZxid());

                // Make sure the data was recorded in the filesystem ok
                ZKDatabase zkDb2 = new ZKDatabase(new FileTxnSnapLog(
                        logDir, snapDir));
                long lastZxid = zkDb2.loadDataBase();
                Assert.assertEquals("data1",
                        new String(zkDb2.getData("/foo1", stat, null)));
                Assert.assertEquals(foo2Zxid, lastZxid);

                // Register watch
                TrackerWatcher watcher = new TrackerWatcher();
                Assert.assertEquals("data1", new String(o.zk
                        .getZKDatabase().getData("/foo2", stat, watcher)));

                // Propose /foo1 update
                long proposalZxid = ZxidUtils.makeZxid(1, 1000);
                proposeSetData(qp, "/foo1", proposalZxid, "data2", 2);
                oa.writeRecord(qp, null);

                // Commit /foo1 update
                qp.setType(Leader.COMMIT);
                qp.setZxid(proposalZxid);
                oa.writeRecord(qp, null);

                // Inform /foo2 update
                long informZxid = ZxidUtils.makeZxid(1, 1001);
                proposeSetData(qp, "/foo2", informZxid, "data2", 2);
                qp.setType(Leader.INFORM);
                oa.writeRecord(qp, null);

                qp.setType(Leader.UPTODATE);
                qp.setZxid(0);
                oa.writeRecord(qp, null);

                // Read the uptodate ack
                readPacketSkippingPing(ia, qp);
                Assert.assertEquals(Leader.ACK, qp.getType());
                Assert.assertEquals(ZxidUtils.makeZxid(1, 0), qp.getZxid());

                // Data should get updated
                watcher.waitForChange();
                Assert.assertEquals("data2", new String(o.zk
                        .getZKDatabase().getData("/foo1", stat, null)));
                Assert.assertEquals("data2", new String(o.zk
                        .getZKDatabase().getData("/foo2", stat, null)));

                // Shutdown sequence guarantee that all pending requests
                // in sync request processor get flush to disk
                o.zk.shutdown();

                zkDb2 = new ZKDatabase(new FileTxnSnapLog(logDir, snapDir));
                lastZxid = zkDb2.loadDataBase();
                Assert.assertEquals("data2", new String(zkDb2.getData("/foo1", stat, null)));
                Assert.assertEquals("data2", new String(zkDb2.getData("/foo2", stat, null)));
                Assert.assertEquals(informZxid, lastZxid);
            } finally {
                recursiveDelete(tmpDir);
            }

        }

        private void proposeSetData(QuorumPacket qp, String path,
                long zxid, String data, int version) throws IOException {
            qp.setType(Leader.PROPOSAL);
            qp.setZxid(zxid);
            TxnHeader hdr = new TxnHeader(4, 1414, qp.getZxid(), 55,
                    ZooDefs.OpCode.setData);
            SetDataTxn sdt = new SetDataTxn(path, data.getBytes(), version);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            OutputArchive boa = BinaryOutputArchive.getArchive(baos);
            boa.writeRecord(hdr, null);
            boa.writeRecord(sdt, null);
            qp.setData(baos.toByteArray());
        }
    });
}




Leader:
1.再次验证选举的ack waitForEpochAck
2.再次验证newLeaderAck waitForNewLeaderAck 边界类是LearnerCnxAcceptor对应的连接LearnerHandler
Observer:1.接受leader会发过来的 Leader.UPTODATE 指令   break outerLoop;2. 处理相关Leader.proposal和Leader.commit.两种的TXN. 
/**
 * This message type is sent by a leader to propose a mutation.
 */
public final static int Leader.PROPOSAL = 2; 进入packetsNotCommitted
/**
 * This message type is sent by a leader to commit a proposal and cause
 * followers to start serving the corresponding data.
 */
final static int Leader.COMMIT = 4; 进入packetsCommitted
FollowerZooKeeperServer fzk = (FollowerZooKeeperServer)zk;
for(PacketInFlight p: packetsNotCommitted) {
    fzk.logRequest(p.hdr, p.rec);
}
for(Long zxid: packetsCommitted) {
    fzk.commit(zxid);
}

魔法数字:
zookeeper 0x10000 代表版本号
Learner类
LearnerInfo li = new LearnerInfo(self.getId(), 0x10000);
Leader里的LearnerHandler类:
  

附录:
zookeeper详细 时序+逻辑流程图.传上来就颠倒了,尴尬.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值