Github user eribeiro commented on a diff in the pull request:
https://github.com/apache/zookeeper/pull/632#discussion_r224206681
--- Diff:
zookeeper-server/src/main/java/org/apache/zookeeper/server/DataTree.java ---
@@ -1521,4 +1566,179 @@ public boolean removeWatch(String path, WatcherType
type, Watcher watcher) {
public ReferenceCountedACLCache getReferenceCountedAclCache() {
return aclCache;
}
+
+ /**
+ * Add the digest to the historical list, and update the latest zxid
digest.
+ */
+ private void logZxidDigest(long zxid, long digest) {
+ ZxidDigest zxidDigest = new ZxidDigest(zxid,
DigestCalculator.DIGEST_VERSION, digest);
+ lastProcessedZxidDigest = zxidDigest;
+ if (zxidDigest.zxid % DIGEST_LOG_INTERVAL == 0) {
+ synchronized (digestLog) {
+ digestLog.add(zxidDigest);
+ if (digestLog.size() > DIGEST_LOG_LIMIT) {
+ digestLog.poll();
+ }
+ }
+ }
+ }
+
+ /**
+ * Serializing the digest to snapshot, this is done after the data
tree
+ * is being serialized, so when we replay the txns and it hits this
zxid
+ * we know we should be in a non-fuzzy state, and have the same
digest.
+ *
+ * @param oa the output stream to write to
+ * @return true if the digest is serialized successfully
+ */
+ public boolean serializeZxidDigest(OutputArchive oa) throws
IOException {
+ if (!DigestCalculator.digestEnabled()) {
+ return false;
+ }
+
+ ZxidDigest zxidDigest = lastProcessedZxidDigest;
+ if (zxidDigest == null) {
+ // write an empty digest
+ zxidDigest = new ZxidDigest();
+ }
+ zxidDigest.serialize(oa);
+ return true;
+ }
+
+ /**
+ * Deserializing the zxid digest from the input stream and update the
+ * digestFromLoadedSnapshot.
+ *
+ * @param ia the input stream to read from
+ * @return the true if it deserialized successfully
+ */
+ public boolean deserializeZxidDigest(InputArchive ia) throws
IOException {
+ if (!DigestCalculator.digestEnabled()) {
+ return false;
+ }
+
+ try {
+ ZxidDigest zxidDigest = new ZxidDigest();
+ zxidDigest.deserialize(ia);
+ if (zxidDigest.zxid > 0) {
+ digestFromLoadedSnapshot = zxidDigest;
+ }
+ return true;
+ } catch (EOFException e) {
+ LOG.warn("Got EOF exception while reading the digest, " +
+ "likely due to the reading an older snapshot.");
+ return false;
+ }
+ }
+
+ /**
+ * Compares the actual tree's digest with that in the snapshot.
+ * Resets digestFromLoadedSnapshot after comparision.
+ *
+ * @param zxid zxid
+ */
+ public void compareSnapshotDigests(long zxid) {
+ if (zxid == digestFromLoadedSnapshot.zxid) {
+ if (DigestCalculator.DIGEST_VERSION !=
digestFromLoadedSnapshot.digestVersion) {
+ LOG.info("Digest version changed, local: {}, new: {}, " +
+ "skip comparing digest now.",
+ digestFromLoadedSnapshot.digestVersion,
DigestCalculator.DIGEST_VERSION);
+ digestFromLoadedSnapshot = null;
+ return;
+ }
+ if (getTreeDigest() != digestFromLoadedSnapshot.getDigest()) {
+ reportDigestMismatch(zxid);
+ }
+ digestFromLoadedSnapshot = null;
+ } else if (digestFromLoadedSnapshot.zxid != 0 && zxid >
digestFromLoadedSnapshot.zxid) {
+ LOG.error("Watching for zxid 0x{} during snapshot recovery, " +
+ "but it wasn't found.",
+ Long.toHexString(digestFromLoadedSnapshot.zxid));
+ }
+ }
+
+ /**
+ * Reports any mismatch in the transaction digest.
+ * @param zxid zxid for which the error is being reported.
+ */
+ public void reportDigestMismatch(long zxid) {
+ ServerMetrics.DIGEST_MISMATCHES_COUNT.add(1);
+ RATE_LOGGER.rateLimitLog("Digests are not matching. Value is
Zxid.",
+ String.valueOf(zxid));
+
+ for (DigestWatcher watcher: digestWatchers) {
+ watcher.process(zxid);
+ }
+ }
+
+ public long getTreeDigest() {
+ return nodes.getDigest();
+ }
+
+ public ZxidDigest getDigestFromLoadedSnapshot() {
+ return digestFromLoadedSnapshot;
+ }
+
+ /**
+ * Add digest mismatch event handler.
+ *
+ * @param digestWatcher the handler to add
+ */
+ public void addDigestWatcher(DigestWatcher digestWatcher) {
+ digestWatchers.add(digestWatcher);
+ }
+
+ /**
+ * Return all the digests in the historical digest list.
+ */
+ public LinkedList<ZxidDigest> getDigestLog() {
+ synchronized (digestLog) {
+ return new LinkedList<ZxidDigest>(digestLog);
--- End diff --
Maybe wrap in `Collections.unmodifiableList()`?
---