aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/vfs/DigestHashFunction.java
diff options
context:
space:
mode:
authorGravatar ccalvarin <ccalvarin@google.com>2018-08-13 10:31:15 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-08-13 10:33:11 -0700
commit37c70a125a0282d331a1ec92397b750d50367551 (patch)
tree6a93a272bbed696544410a13405255d66aa5cddd /src/main/java/com/google/devtools/build/lib/vfs/DigestHashFunction.java
parent6ab4e16b89aca166fdee85628e264eb6ca5288af (diff)
Add easy access to MessageDigests in DigestHashFunction
Move the message-digest cloning to DigestHashFunction and out of Fingerprint, to make it possible to configure Fingerprint to use different hash functions. We keep the default MD5 for now, we'd like it to use the global default but want to isolate the configuration change from any change adding potential contention. RELNOTES: None. PiperOrigin-RevId: 208502993
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/vfs/DigestHashFunction.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/vfs/DigestHashFunction.java99
1 files changed, 80 insertions, 19 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/DigestHashFunction.java b/src/main/java/com/google/devtools/build/lib/vfs/DigestHashFunction.java
index 12aee0757b..123e4b5a9c 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/DigestHashFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/DigestHashFunction.java
@@ -14,16 +14,26 @@
package com.google.devtools.build.lib.vfs;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import com.google.devtools.common.options.Converter;
import com.google.devtools.common.options.OptionsParsingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
-/** Type of hash function to use for digesting files. */
+/**
+ * Type of hash function to use for digesting files.
+ *
+ * <p>This tracks parallel {@link java.security.MessageDigest} and {@link HashFunction} interfaces
+ * for each provided hash, as Bazel uses both - MessageDigest where performance is critical and
+ * HashFunctions where ease-of-use wins over.
+ */
// The underlying HashFunctions are immutable and thread safe.
public class DigestHashFunction {
// This map must be declared first to make sure that calls to register() have it ready.
@@ -36,33 +46,24 @@ public class DigestHashFunction {
private static DigestHashFunction defaultHash;
private static boolean defaultHasBeenSet = false;
- private final HashFunction hash;
+ private final HashFunction hashFunction;
private final String name;
+ private final MessageDigest messageDigestPrototype;
+ private final boolean messageDigestPrototypeSupportsClone;
- private DigestHashFunction(HashFunction hash, String name) {
- this.hash = hash;
+ private DigestHashFunction(HashFunction hashFunction, String name) {
+ this.hashFunction = hashFunction;
this.name = name;
- }
-
- public HashFunction getHash() {
- return hash;
- }
-
- public boolean isValidDigest(byte[] digest) {
- // TODO(b/109764197): Remove this check to accept variable-length hashes.
- return digest != null && digest.length * 8 == hash.bits();
- }
-
- @Override
- public String toString() {
- return name;
+ this.messageDigestPrototype = getMessageDigestInstance();
+ this.messageDigestPrototypeSupportsClone = supportsClone(messageDigestPrototype);
}
/**
* Creates a new DigestHashFunction that is registered to be recognized by its name in {@link
* DigestFunctionConverter}.
*
- * @param hashName the canonical name for this hash function.
+ * @param hashName the canonical name for this hash function - and the name that can be used to
+ * uncover the MessageDigest.
* @param altNames alternative names that will be mapped to this function by the converter but
* will not serve as the canonical name for the DigestHashFunction.
* @param hash The {@link HashFunction} to register.
@@ -70,6 +71,15 @@ public class DigestHashFunction {
*/
public static DigestHashFunction register(
HashFunction hash, String hashName, String... altNames) {
+ try {
+ MessageDigest.getInstance(hashName);
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException(
+ "The hash function name provided does not correspond to a valid MessageDigest: "
+ + hashName,
+ e);
+ }
+
DigestHashFunction hashFunction = new DigestHashFunction(hash, hashName);
List<String> names = ImmutableList.<String>builder().add(hashName).add(altNames).build();
synchronized (hashFunctionRegistry) {
@@ -149,4 +159,55 @@ public class DigestHashFunction {
return "hash function";
}
}
+
+ public HashFunction getHashFunction() {
+ return hashFunction;
+ }
+
+ public MessageDigest cloneOrCreateMessageDigest() {
+ if (messageDigestPrototypeSupportsClone) {
+ try {
+ return (MessageDigest) messageDigestPrototype.clone();
+ } catch (CloneNotSupportedException e) {
+ // We checked at initialization that this could be cloned, so this should never happen.
+ throw new IllegalStateException("Could not clone message digest", e);
+ }
+ } else {
+ return getMessageDigestInstance();
+ }
+ }
+
+ public boolean isValidDigest(byte[] digest) {
+ // TODO(b/109764197): Remove this check to accept variable-length hashes.
+ return digest != null && digest.length * 8 == hashFunction.bits();
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ private MessageDigest getMessageDigestInstance() {
+ try {
+ return MessageDigest.getInstance(name);
+ } catch (NoSuchAlgorithmException e) {
+ // We check when we register() this digest function that the message digest exists. This
+ // should never happen.
+ throw new IllegalStateException("message digest " + name + " not available", e);
+ }
+ }
+
+ private static boolean supportsClone(MessageDigest toCheck) {
+ try {
+ toCheck.clone();
+ return true;
+ } catch (CloneNotSupportedException e) {
+ return false;
+ }
+ }
+
+ @VisibleForTesting
+ static Collection<DigestHashFunction> getPossibleHashFunctions() {
+ return hashFunctionRegistry.values();
+ }
}