From a78d326f0ecbc5113dd76f0a436e9b3abd353a36 Mon Sep 17 00:00:00 2001 From: asdf2014 Date: Sun, 3 Mar 2019 19:59:31 +0800 Subject: [PATCH] ZOOKEEPER-2789: Reassign `ZXID` for solving 32bit overflow problem --- .../apache/zookeeper/graph/JsonGenerator.java | 17 +++---- .../quorum/FollowerZooKeeperServer.java | 3 +- .../zookeeper/server/quorum/Leader.java | 8 +-- .../server/quorum/LearnerHandler.java | 4 +- .../zookeeper/server/util/ZxidUtils.java | 49 ++++++++++++++----- .../zookeeper/server/ZxidRolloverTest.java | 3 +- .../server/quorum/LearnerHandlerTest.java | 2 +- .../test/FollowerResyncConcurrencyTest.java | 5 +- .../apache/zookeeper/test/ReconfigTest.java | 4 +- 9 files changed, 59 insertions(+), 36 deletions(-) diff --git a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/JsonGenerator.java b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/JsonGenerator.java index 8215833f298..1c88fada329 100644 --- a/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/JsonGenerator.java +++ b/zookeeper-contrib/zookeeper-contrib-loggraph/src/main/java/org/apache/zookeeper/graph/JsonGenerator.java @@ -17,20 +17,15 @@ */ package org.apache.zookeeper.graph; - +import org.apache.zookeeper.server.util.ZxidUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.JSONValue; -import java.io.Writer; -import java.io.OutputStreamWriter; -import java.io.IOException; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedList; -import java.util.ListIterator; import java.util.Set; public class JsonGenerator { @@ -122,8 +117,8 @@ public JsonGenerator(LogIterator iter) { } else if ((m = newElectionP.matcher(e.getEntry())).find()) { Iterator iterator = servers.iterator(); long zxid = Long.valueOf(m.group(2)); - int count = (int)zxid;// & 0xFFFFFFFFL; - int epoch = (int)Long.rotateRight(zxid, 32);// >> 32; + long count = ZxidUtils.getCounterFromZxid(zxid); + long epoch = ZxidUtils.getEpochFromZxid(zxid); if (leader != 0 && epoch > curEpoch) { JSONObject stateChange = new JSONObject(); @@ -156,9 +151,9 @@ public JsonGenerator(LogIterator iter) { long zxid = Long.valueOf(m.group(2)); int dst = e.getNode(); long epoch2 = Long.valueOf(m.group(3)); - - int count = (int)zxid;// & 0xFFFFFFFFL; - int epoch = (int)Long.rotateRight(zxid, 32);// >> 32; + + long count = ZxidUtils.getCounterFromZxid(zxid); + long epoch = ZxidUtils.getEpochFromZxid(zxid); if (leader != 0 && epoch > curEpoch) { JSONObject stateChange = new JSONObject(); diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/FollowerZooKeeperServer.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/FollowerZooKeeperServer.java index 610e965df17..f162196f9eb 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/FollowerZooKeeperServer.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/FollowerZooKeeperServer.java @@ -24,6 +24,7 @@ import org.apache.jute.Record; import org.apache.zookeeper.jmx.MBeanRegistry; +import org.apache.zookeeper.server.util.ZxidUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.zookeeper.server.ExitCode; @@ -87,7 +88,7 @@ protected void setupRequestProcessors() { public void logRequest(TxnHeader hdr, Record txn) { Request request = new Request(hdr.getClientId(), hdr.getCxid(), hdr.getType(), hdr, txn, hdr.getZxid()); - if ((request.zxid & 0xffffffffL) != 0) { + if (ZxidUtils.getCounterFromZxid(request.zxid) != 0) { pendingTxns.add(request); } syncProcessor.processRequest(request); diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Leader.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Leader.java index c284debfc49..f7440687e9e 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Leader.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Leader.java @@ -533,7 +533,7 @@ void lead() throws IOException, InterruptedException { null, null); - if ((newLeaderProposal.packet.getZxid() & 0xffffffffL) != 0) { + if (ZxidUtils.getCounterFromZxid(newLeaderProposal.packet.getZxid()) != 0) { LOG.info("NEWLEADER proposal has Zxid of " + Long.toHexString(newLeaderProposal.packet.getZxid())); } @@ -624,7 +624,7 @@ void lead() throws IOException, InterruptedException { String initialZxid = System.getProperty("zookeeper.testingonly.initialZxid"); if (initialZxid != null) { long zxid = Long.parseLong(initialZxid); - zk.setZxid((zk.getZxid() & 0xffffffff00000000L) | zxid); + zk.setZxid(ZxidUtils.clearCounter(zk.getZxid()) | zxid); } if (!System.getProperty("zookeeper.leaderServes", "yes").equals("no")) { @@ -898,7 +898,7 @@ synchronized public void processAck(long sid, long zxid, SocketAddress followerA LOG.trace("outstanding proposals all"); } - if ((zxid & 0xffffffffL) == 0) { + if (ZxidUtils.getCounterFromZxid(zxid) == 0) { /* * We no longer process NEWLEADER ack with this method. However, * the learner sends an ack back to the leader after it gets @@ -1135,7 +1135,7 @@ public Proposal propose(Request request) throws XidRolloverException { * Address the rollover issue. All lower 32bits set indicate a new leader * election. Force a re-election instead. See ZOOKEEPER-1277 */ - if ((request.zxid & 0xffffffffL) == 0xffffffffL) { + if (ZxidUtils.getCounterFromZxid(request.zxid) == ZxidUtils.getCounterLowPosition()) { String msg = "zxid lower 32 bits have rolled over, forcing re-election, and therefore new epoch start"; shutdown(msg); diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LearnerHandler.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LearnerHandler.java index 78429e0e037..e84438d6872 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LearnerHandler.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LearnerHandler.java @@ -669,7 +669,7 @@ boolean syncFollower(long peerLastZxid, LearnerMaster learnerMaster) { * zxid in our history. In this case, we will ignore TRUNC logic and * always send DIFF if we have old enough history */ - boolean isPeerNewEpochZxid = (peerLastZxid & 0xffffffffL) == 0; + boolean isPeerNewEpochZxid = ZxidUtils.getCounterFromZxid(peerLastZxid) == 0; // Keep track of the latest zxid which already queued long currentZxid = peerLastZxid; boolean needSnap = true; @@ -818,7 +818,7 @@ boolean syncFollower(long peerLastZxid, LearnerMaster learnerMaster) { */ protected long queueCommittedProposals(Iterator itr, long peerLastZxid, Long maxZxid, Long lastCommittedZxid) { - boolean isPeerNewEpochZxid = (peerLastZxid & 0xffffffffL) == 0; + boolean isPeerNewEpochZxid = ZxidUtils.getCounterFromZxid(peerLastZxid) == 0; long queuedZxid = peerLastZxid; // as we look through proposals, this variable keeps track of previous // proposal Id. diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/util/ZxidUtils.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/util/ZxidUtils.java index 39e076a27ef..a9253728af9 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/util/ZxidUtils.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/util/ZxidUtils.java @@ -19,16 +19,41 @@ package org.apache.zookeeper.server.util; public class ZxidUtils { - static public long getEpochFromZxid(long zxid) { - return zxid >> 32L; - } - static public long getCounterFromZxid(long zxid) { - return zxid & 0xffffffffL; - } - static public long makeZxid(long epoch, long counter) { - return (epoch << 32L) | (counter & 0xffffffffL); - } - static public String zxidToString(long zxid) { - return Long.toHexString(zxid); - } + + private static final long EPOCH_HIGH_POSITION = 40L; + private static final long COUNTER_LOW_POSITION = 0xffffffffffL; + private static final long CLEAR_EPOCH = 0x000000ffffffffffL; + private static final long CLEAR_COUNTER = 0xffffff0000000000L; + + static public long getEpochFromZxid(long zxid) { + return zxid >> EPOCH_HIGH_POSITION; + } + + static public long getCounterFromZxid(long zxid) { + return zxid & COUNTER_LOW_POSITION; + } + + static public long makeZxid(long epoch, long counter) { + return (epoch << EPOCH_HIGH_POSITION) | (counter & COUNTER_LOW_POSITION); + } + + static public long clearEpoch(long zxid) { + return zxid & CLEAR_EPOCH; + } + + static public long clearCounter(long zxid) { + return zxid & CLEAR_COUNTER; + } + + static public String zxidToString(long zxid) { + return Long.toHexString(zxid); + } + + public static long getEpochHighPosition() { + return EPOCH_HIGH_POSITION; + } + + public static long getCounterLowPosition() { + return COUNTER_LOW_POSITION; + } } diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/server/ZxidRolloverTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/server/ZxidRolloverTest.java index 838b0a80954..debf8801f4a 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/server/ZxidRolloverTest.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/server/ZxidRolloverTest.java @@ -25,6 +25,7 @@ import org.apache.zookeeper.ZKTestCase; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooKeeper; +import org.apache.zookeeper.server.util.ZxidUtils; import org.apache.zookeeper.test.ClientBase; import org.apache.zookeeper.test.ClientBase.CountdownWatcher; import org.apache.zookeeper.test.ClientTest; @@ -207,7 +208,7 @@ private void shutdown(int idx) throws Exception { /** Reset the next zxid to be near epoch end */ private void adjustEpochNearEnd() { - zksLeader.setZxid((zksLeader.getZxid() & 0xffffffff00000000L) | 0xfffffffcL); + zksLeader.setZxid(ZxidUtils.clearCounter(zksLeader.getZxid()) | 0xfffffffffcL); } @After diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/LearnerHandlerTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/LearnerHandlerTest.java index 1cd33ec9178..5cdbd4ac06d 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/LearnerHandlerTest.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/LearnerHandlerTest.java @@ -484,7 +484,7 @@ public void testNewEpochZxid() throws Exception { /** * Test cases when learner has new-epcoh zxid - * (zxid & 0xffffffffL) == 0; + * (zxid & 0xffffffffffL) == 0; */ @Test public void testNewEpochZxidWithTxnlogOnly() throws Exception { diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/FollowerResyncConcurrencyTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/FollowerResyncConcurrencyTest.java index 50867113653..461f7009aae 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/test/FollowerResyncConcurrencyTest.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/FollowerResyncConcurrencyTest.java @@ -46,6 +46,7 @@ import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.server.ZKDatabase; import org.apache.zookeeper.server.quorum.Leader; +import org.apache.zookeeper.server.util.ZxidUtils; import org.apache.zookeeper.test.ClientBase.CountdownWatcher; import org.junit.After; import org.junit.Assert; @@ -613,8 +614,8 @@ private static TestableZooKeeper createTestableClient( private void verifyState(QuorumUtil qu, int index, Leader leader) { LOG.info("Verifying state"); assertTrue("Not following", qu.getPeer(index).peer.follower != null); - long epochF = (qu.getPeer(index).peer.getActiveServer().getZxid() >> 32L); - long epochL = (leader.getEpoch() >> 32L); + long epochF = ZxidUtils.getEpochFromZxid(qu.getPeer(index).peer.getActiveServer().getZxid()); + long epochL = ZxidUtils.getEpochFromZxid(leader.getEpoch()); assertTrue("Zxid: " + qu.getPeer(index).peer.getActiveServer().getZKDatabase().getDataTreeLastProcessedZxid() + "Current epoch: " + epochF, epochF == epochL); int leaderIndex = (index == 1) ? 2 : 1; diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ReconfigTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ReconfigTest.java index 2015fe59a81..a2570080efd 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ReconfigTest.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ReconfigTest.java @@ -884,7 +884,7 @@ public void testQuorumSystemChange() throws Exception { + " doesn't think the quorum system is a majority quorum system!"); } } - + @Test public void testInitialConfigHasPositiveVersion() throws Exception { qu = new QuorumUtil(1); // create 3 servers @@ -896,7 +896,7 @@ public void testInitialConfigHasPositiveVersion() throws Exception { String configStr = testServerHasConfig(zkArr[i], null, null); QuorumVerifier qv = qu.getPeer(i).peer.configFromString(configStr); long version = qv.getVersion(); - Assert.assertTrue(version == 0x100000000L); + Assert.assertTrue(version == 0x10000000000L); } }