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()`?
---