You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ju...@apache.org on 2013/09/27 02:11:33 UTC
svn commit: r1526757 - in
/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak:
api/Blob.java plugins/memory/AbstractBlob.java
Author: jukka
Date: Fri Sep 27 00:11:33 2013
New Revision: 1526757
URL: http://svn.apache.org/r1526757
Log:
OAK-1050: Remove Blob.sha256()
As a followup add better definition of equals() and hashCode() for Blobs
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Blob.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Blob.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Blob.java?rev=1526757&r1=1526756&r2=1526757&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Blob.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Blob.java Fri Sep 27 00:11:33 2013
@@ -24,6 +24,16 @@ import javax.annotation.Nonnull;
/**
* Immutable representation of a binary value of finite length.
+ * <p>
+ * Two blobs are considered equal in terms of {@link Object#equals(Object)}
+ * if they contain the same sequences of bytes. Implementations can optimize
+ * the equality checks by using strong hash codes or other similar means as
+ * long as they comply with the above definition of equality.
+ * <p>
+ * Due to their nature blobs should not be used as keys in hash tables.
+ * To highlight that and to ensure semantic correctness of the equality
+ * contract across different blob implementations, the {@link #hashCode()}
+ * method of all blob instances should return zero.
*/
public interface Blob {
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java?rev=1526757&r1=1526756&r2=1526757&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java Fri Sep 27 00:11:33 2013
@@ -20,7 +20,6 @@ package org.apache.jackrabbit.oak.plugin
import java.io.IOException;
import java.io.InputStream;
-import java.util.Arrays;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
@@ -36,25 +35,40 @@ import org.apache.jackrabbit.oak.api.Blo
*/
public abstract class AbstractBlob implements Blob {
+ private static class BlobSupplier implements InputSupplier<InputStream> {
+
+ private final Blob blob;
+
+ private BlobSupplier(Blob blob) {
+ this.blob = blob;
+ }
+
+ @Override
+ public InputStream getInput() throws IOException {
+ return blob.getNewStream();
+ }
+
+ }
+
+ private static boolean equal(Blob a, Blob b) {
+ try {
+ return ByteStreams.equal(new BlobSupplier(a), new BlobSupplier(b));
+ } catch (IOException e) {
+ throw new RuntimeException("Blob equality check failed", e);
+ }
+ }
+
private static HashCode calculateSha256(final Blob blob) {
try {
- return ByteStreams.hash(
- new InputSupplier<InputStream>() {
- @Override
- public InputStream getInput() throws IOException {
- return blob.getNewStream();
- }
- },
- Hashing.sha256());
+ return ByteStreams.hash(new BlobSupplier(blob), Hashing.sha256());
} catch (IOException e) {
- throw new RuntimeException(
- "Failed to calculate the hash code of a stream", e);
+ throw new RuntimeException("Blob hash calculation failed", e);
}
}
- private HashCode hashCode = null;
+ private HashCode hashCode = null; // synchronized access
- private synchronized HashCode calculateSha256() {
+ private synchronized HashCode getSha256() {
// Blobs are immutable so we can safely cache the hash
if (hashCode == null) {
hashCode = calculateSha256(this);
@@ -66,13 +80,8 @@ public abstract class AbstractBlob imple
* This hash code implementation returns the hash code of the underlying stream
* @return
*/
- @Override
- public int hashCode() {
- return calculateSha256().asInt();
- }
-
protected byte[] sha256() {
- return calculateSha256().asBytes();
+ return getSha256().asBytes();
}
/**
@@ -85,21 +94,34 @@ public abstract class AbstractBlob imple
public boolean equals(Object other) {
if (other == this) {
return true;
- } else if (other instanceof AbstractBlob) {
+ }
+
+ if (other instanceof AbstractBlob) {
AbstractBlob that = (AbstractBlob) other;
- return Arrays.equals(sha256(), that.sha256());
- } else if (other instanceof Blob) {
- Blob that = (Blob) other;
- return Arrays.equals(sha256(), calculateSha256(that).asBytes());
- } else {
- return false;
+ // optimize the comparison if both this and the other blob
+ // already have pre-computed SHA-256 hash codes
+ synchronized (this) {
+ if (hashCode != null) {
+ synchronized (that) {
+ if (that.hashCode != null) {
+ return hashCode.equals(that.hashCode);
+ }
+ }
+ }
+ }
}
+
+ return other instanceof Blob && equal(this, (Blob) other);
}
@Override
- public String toString() {
- return calculateSha256().toString();
+ public int hashCode() {
+ return 0; // see Blob javadoc
}
+ @Override
+ public String toString() {
+ return getSha256().toString();
+ }
}