|
@@ -82,6 +82,10 @@ public class Learner {
|
|
Record rec;
|
|
Record rec;
|
|
TxnDigest digest;
|
|
TxnDigest digest;
|
|
|
|
|
|
|
|
+ Request toRequest() {
|
|
|
|
+ return new Request(hdr, rec, digest);
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
QuorumPeer self;
|
|
QuorumPeer self;
|
|
@@ -535,6 +539,27 @@ public class Learner {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ long enforceContinuousProposal(long lastQueued, PacketInFlight pif) throws Exception {
|
|
|
|
+ if (lastQueued == 0) {
|
|
|
|
+ LOG.info("DIFF sync got first proposal 0x{}", Long.toHexString(pif.hdr.getZxid()));
|
|
|
|
+ } else if (pif.hdr.getZxid() != lastQueued + 1) {
|
|
|
|
+ if (ZxidUtils.getEpochFromZxid(pif.hdr.getZxid()) <= ZxidUtils.getEpochFromZxid(lastQueued)) {
|
|
|
|
+ String msg = String.format(
|
|
|
|
+ "DIFF sync got proposal 0x%s, last queued 0x%s, expected 0x%s",
|
|
|
|
+ Long.toHexString(pif.hdr.getZxid()), Long.toHexString(lastQueued),
|
|
|
|
+ Long.toHexString(lastQueued + 1));
|
|
|
|
+ LOG.error(msg);
|
|
|
|
+ throw new Exception(msg);
|
|
|
|
+ }
|
|
|
|
+ // We can't tell whether it is a data loss. Given that new epoch is rare,
|
|
|
|
+ // log at warn should not be too verbose.
|
|
|
|
+ LOG.warn("DIFF sync got new epoch proposal 0x{}, last queued 0x{}, expected 0x{}",
|
|
|
|
+ Long.toHexString(pif.hdr.getZxid()), Long.toHexString(lastQueued),
|
|
|
|
+ Long.toHexString(lastQueued + 1));
|
|
|
|
+ }
|
|
|
|
+ return pif.hdr.getZxid();
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Finally, synchronize our history with the Leader (if Follower)
|
|
* Finally, synchronize our history with the Leader (if Follower)
|
|
* or the LearnerMaster (if Observer).
|
|
* or the LearnerMaster (if Observer).
|
|
@@ -609,6 +634,8 @@ public class Learner {
|
|
zk.getZKDatabase().initConfigInZKDatabase(self.getQuorumVerifier());
|
|
zk.getZKDatabase().initConfigInZKDatabase(self.getQuorumVerifier());
|
|
zk.createSessionTracker();
|
|
zk.createSessionTracker();
|
|
|
|
|
|
|
|
+ // TODO: Ideally, this should be lastProcessZxid(a.k.a. QuorumPacket::zxid from above), but currently
|
|
|
|
+ // LearnerHandler does not guarantee this. So, let's be conservative and keep it unchange for now.
|
|
long lastQueued = 0;
|
|
long lastQueued = 0;
|
|
|
|
|
|
// in Zab V1.0 (ZK 3.4+) we might take a snapshot when we get the NEWLEADER message, but in pre V1.0
|
|
// in Zab V1.0 (ZK 3.4+) we might take a snapshot when we get the NEWLEADER message, but in pre V1.0
|
|
@@ -630,13 +657,7 @@ public class Learner {
|
|
pif.hdr = logEntry.getHeader();
|
|
pif.hdr = logEntry.getHeader();
|
|
pif.rec = logEntry.getTxn();
|
|
pif.rec = logEntry.getTxn();
|
|
pif.digest = logEntry.getDigest();
|
|
pif.digest = logEntry.getDigest();
|
|
- if (pif.hdr.getZxid() != lastQueued + 1) {
|
|
|
|
- LOG.warn(
|
|
|
|
- "Got zxid 0x{} expected 0x{}",
|
|
|
|
- Long.toHexString(pif.hdr.getZxid()),
|
|
|
|
- Long.toHexString(lastQueued + 1));
|
|
|
|
- }
|
|
|
|
- lastQueued = pif.hdr.getZxid();
|
|
|
|
|
|
+ lastQueued = enforceContinuousProposal(lastQueued, pif);
|
|
|
|
|
|
if (pif.hdr.getType() == OpCode.reconfig) {
|
|
if (pif.hdr.getType() == OpCode.reconfig) {
|
|
SetDataTxn setDataTxn = (SetDataTxn) pif.rec;
|
|
SetDataTxn setDataTxn = (SetDataTxn) pif.rec;
|
|
@@ -666,7 +687,7 @@ public class Learner {
|
|
Long.toHexString(qp.getZxid()),
|
|
Long.toHexString(qp.getZxid()),
|
|
Long.toHexString(pif.hdr.getZxid()));
|
|
Long.toHexString(pif.hdr.getZxid()));
|
|
} else {
|
|
} else {
|
|
- zk.processTxn(pif.hdr, pif.rec);
|
|
|
|
|
|
+ zk.processTxn(pif.toRequest());
|
|
packetsNotLogged.remove();
|
|
packetsNotLogged.remove();
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
@@ -696,18 +717,11 @@ public class Learner {
|
|
packet.rec = logEntry.getTxn();
|
|
packet.rec = logEntry.getTxn();
|
|
packet.hdr = logEntry.getHeader();
|
|
packet.hdr = logEntry.getHeader();
|
|
packet.digest = logEntry.getDigest();
|
|
packet.digest = logEntry.getDigest();
|
|
- // Log warning message if txn comes out-of-order
|
|
|
|
- if (packet.hdr.getZxid() != lastQueued + 1) {
|
|
|
|
- LOG.warn(
|
|
|
|
- "Got zxid 0x{} expected 0x{}",
|
|
|
|
- Long.toHexString(packet.hdr.getZxid()),
|
|
|
|
- Long.toHexString(lastQueued + 1));
|
|
|
|
- }
|
|
|
|
- lastQueued = packet.hdr.getZxid();
|
|
|
|
|
|
+ lastQueued = enforceContinuousProposal(lastQueued, packet);
|
|
}
|
|
}
|
|
if (!writeToTxnLog) {
|
|
if (!writeToTxnLog) {
|
|
// Apply to db directly if we haven't taken the snapshot
|
|
// Apply to db directly if we haven't taken the snapshot
|
|
- zk.processTxn(packet.hdr, packet.rec);
|
|
|
|
|
|
+ zk.processTxn(packet.toRequest());
|
|
} else {
|
|
} else {
|
|
packetsNotLogged.add(packet);
|
|
packetsNotLogged.add(packet);
|
|
packetsCommitted.add(qp.getZxid());
|
|
packetsCommitted.add(qp.getZxid());
|
|
@@ -780,8 +794,9 @@ public class Learner {
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
packetsNotLogged.removeFirst();
|
|
packetsNotLogged.removeFirst();
|
|
- fzk.appendRequest(pif.hdr, pif.rec, pif.digest);
|
|
|
|
- fzk.processTxn(pif.hdr, pif.rec);
|
|
|
|
|
|
+ Request request = pif.toRequest();
|
|
|
|
+ fzk.appendRequest(request);
|
|
|
|
+ fzk.processTxn(request);
|
|
}
|
|
}
|
|
|
|
|
|
// @see https://issues.apache.org/jira/browse/ZOOKEEPER-4646
|
|
// @see https://issues.apache.org/jira/browse/ZOOKEEPER-4646
|
|
@@ -823,7 +838,7 @@ public class Learner {
|
|
if (zk instanceof FollowerZooKeeperServer) {
|
|
if (zk instanceof FollowerZooKeeperServer) {
|
|
FollowerZooKeeperServer fzk = (FollowerZooKeeperServer) zk;
|
|
FollowerZooKeeperServer fzk = (FollowerZooKeeperServer) zk;
|
|
for (PacketInFlight p : packetsNotLogged) {
|
|
for (PacketInFlight p : packetsNotLogged) {
|
|
- fzk.logRequest(p.hdr, p.rec, p.digest);
|
|
|
|
|
|
+ fzk.logRequest(p.toRequest());
|
|
}
|
|
}
|
|
LOG.info("{} txns have been logged asynchronously", packetsNotLogged.size());
|
|
LOG.info("{} txns have been logged asynchronously", packetsNotLogged.size());
|
|
|
|
|
|
@@ -847,8 +862,7 @@ public class Learner {
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
packetsCommitted.remove();
|
|
packetsCommitted.remove();
|
|
- Request request = new Request(p.hdr.getClientId(), p.hdr.getCxid(), p.hdr.getType(), p.hdr, p.rec, -1);
|
|
|
|
- request.setTxnDigest(p.digest);
|
|
|
|
|
|
+ Request request = p.toRequest();
|
|
ozk.commitRequest(request);
|
|
ozk.commitRequest(request);
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|