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();
+    }
 
 }