aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/util/Fingerprint.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/util/Fingerprint.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/util/Fingerprint.java80
1 files changed, 28 insertions, 52 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/util/Fingerprint.java b/src/main/java/com/google/devtools/build/lib/util/Fingerprint.java
index a2bafa6f6a..556bafdb0a 100644
--- a/src/main/java/com/google/devtools/build/lib/util/Fingerprint.java
+++ b/src/main/java/com/google/devtools/build/lib/util/Fingerprint.java
@@ -15,6 +15,7 @@
package com.google.devtools.build.lib.util;
import com.google.common.io.ByteStreams;
+import com.google.devtools.build.lib.vfs.DigestHashFunction;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.protobuf.CodedOutputStream;
@@ -23,47 +24,45 @@ import java.nio.charset.StandardCharsets;
import java.security.DigestException;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
import javax.annotation.Nullable;
/**
- * Simplified wrapper for MD5 message digests.
+ * Simplified wrapper for computing message digests.
*
* @see java.security.MessageDigest
*/
public final class Fingerprint implements Consumer<String> {
- private static final MessageDigest MD5_PROTOTYPE;
- private static final boolean MD5_PROTOTYPE_SUPPORTS_CLONE;
-
- static {
- MD5_PROTOTYPE = getMd5Instance();
- MD5_PROTOTYPE_SUPPORTS_CLONE = supportsClone(MD5_PROTOTYPE);
- }
-
// Make novel use of a CodedOutputStream, which is good at efficiently serializing data. By
// flushing at the end of each digest we can continue to use the stream.
private final CodedOutputStream codedOut;
- private final MessageDigest md5;
+ private final MessageDigest messageDigest;
/** Creates and initializes a new instance. */
- public Fingerprint() {
- md5 = cloneOrCreateMd5();
+ public Fingerprint(DigestHashFunction digestFunction) {
+ messageDigest = digestFunction.cloneOrCreateMessageDigest();
// This is a lot of indirection, but CodedOutputStream does a reasonable job of converting
// strings to bytes without creating a whole bunch of garbage, which pays off.
- codedOut = CodedOutputStream.newInstance(
- new DigestOutputStream(ByteStreams.nullOutputStream(), md5),
- /*bufferSize=*/ 1024);
+ codedOut =
+ CodedOutputStream.newInstance(
+ new DigestOutputStream(ByteStreams.nullOutputStream(), messageDigest),
+ /*bufferSize=*/ 1024);
+ }
+
+ public Fingerprint() {
+ // TODO(b/112460990): Use the value from DigestHashFunction.getDefault(), but check for
+ // contention.
+ this(DigestHashFunction.MD5);
}
/**
* Completes the hash computation by doing final operations and resets the underlying state,
* allowing this instance to be used again.
*
- * @return the MD5 digest as a 16-byte array
+ * @return the digest as a 16-byte array
* @see java.security.MessageDigest#digest()
*/
public byte[] digestAndReset() {
@@ -72,7 +71,7 @@ public final class Fingerprint implements Consumer<String> {
} catch (IOException e) {
throw new IllegalStateException("failed to flush", e);
}
- return md5.digest();
+ return messageDigest.digest();
}
/**
@@ -87,7 +86,7 @@ public final class Fingerprint implements Consumer<String> {
public void digestAndReset(byte[] buf, int offset, int len) {
try {
codedOut.flush();
- md5.digest(buf, offset, len);
+ messageDigest.digest(buf, offset, len);
} catch (IOException e) {
throw new IllegalStateException("failed to flush", e);
} catch (DigestException e) {
@@ -250,18 +249,6 @@ public final class Fingerprint implements Consumer<String> {
return this;
}
- private static MessageDigest cloneOrCreateMd5() {
- if (MD5_PROTOTYPE_SUPPORTS_CLONE) {
- try {
- return (MessageDigest) MD5_PROTOTYPE.clone();
- } catch (CloneNotSupportedException e) {
- throw new IllegalStateException("Could not clone md5", e);
- }
- } else {
- return getMd5Instance();
- }
- }
-
private static String hexDigest(byte[] digest) {
StringBuilder b = new StringBuilder(32);
for (int i = 0; i < digest.length; i++) {
@@ -272,33 +259,22 @@ public final class Fingerprint implements Consumer<String> {
return b.toString();
}
- private static MessageDigest getMd5Instance() {
- try {
- return MessageDigest.getInstance("md5");
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException("md5 not available", e);
- }
- }
-
- private static boolean supportsClone(MessageDigest toCheck) {
- try {
- toCheck.clone();
- return true;
- } catch (CloneNotSupportedException e) {
- return false;
- }
- }
-
// -------- Convenience methods ----------------------------
/**
- * Computes the hex digest from a String using UTF8 encoding and returning
- * the hexDigest().
+ * Computes the hex digest from a String using UTF8 encoding and returning the hexDigest().
*
* @param input the String from which to compute the digest
*/
- public static String md5Digest(String input) {
- return hexDigest(cloneOrCreateMd5().digest(input.getBytes(StandardCharsets.UTF_8)));
+ public static String getHexDigest(String input) {
+ // TODO(b/112460990): This convenience method, if kept should not use MD5 by default, but should
+ // use the value from DigestHashFunction.getDefault(). However, this gets called during class
+ // loading in a few places, before setDefault() has been called, so these call-sites should be
+ // removed before this can be done safely.
+ return hexDigest(
+ DigestHashFunction.MD5
+ .cloneOrCreateMessageDigest()
+ .digest(input.getBytes(StandardCharsets.UTF_8)));
}
@Override