From 9bf494024957faa45a2c13199085b5c68cafbae4 Mon Sep 17 00:00:00 2001 From: Alec Grieser Date: Sun, 17 Feb 2019 10:40:38 -0800 Subject: [PATCH] Memoize Tuple hashes and do not pack for equality check --- .../apple/foundationdb/subspace/Subspace.java | 2 +- .../com/apple/foundationdb/tuple/Tuple.java | 23 ++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/bindings/java/src/main/com/apple/foundationdb/subspace/Subspace.java b/bindings/java/src/main/com/apple/foundationdb/subspace/Subspace.java index 26bc34177e..59c3f94329 100644 --- a/bindings/java/src/main/com/apple/foundationdb/subspace/Subspace.java +++ b/bindings/java/src/main/com/apple/foundationdb/subspace/Subspace.java @@ -228,7 +228,7 @@ public class Subspace { if(!contains(key)) throw new IllegalArgumentException("Cannot unpack key that is not contained in subspace."); - return Tuple.fromBytes(Arrays.copyOfRange(key, rawPrefix.length, key.length)); + return Tuple.fromBytes(key, rawPrefix.length, key.length - rawPrefix.length); } /** diff --git a/bindings/java/src/main/com/apple/foundationdb/tuple/Tuple.java b/bindings/java/src/main/com/apple/foundationdb/tuple/Tuple.java index 50f023d572..557432d4e3 100644 --- a/bindings/java/src/main/com/apple/foundationdb/tuple/Tuple.java +++ b/bindings/java/src/main/com/apple/foundationdb/tuple/Tuple.java @@ -71,6 +71,7 @@ public class Tuple implements Comparable, Iterable { private static IterableComparator comparator = new IterableComparator(); private List elements; + private int memoizedHash = 0; private Tuple(List elements, Object newItem) { this(elements); @@ -759,14 +760,28 @@ public class Tuple implements Comparable, Iterable { } /** - * Returns a hash code value for this {@code Tuple}. + * Returns a hash code value for this {@code Tuple}. Computing the hash code is fairly expensive + * as it involves packing the underlying {@code Tuple} to bytes. However, this value is memoized, + * so for any given {@code Tuple}, it only needs to be computed once. This means that it is + * generally safe to use {@code Tuple}s with hash-based data structures such as + * {@link java.util.HashSet HashSet}s or {@link java.util.HashMap HashMap}s. * {@inheritDoc} * * @return a hash code for this {@code Tuple} that can be used by hash tables */ @Override public int hashCode() { - return Arrays.hashCode(this.pack()); + if(memoizedHash == 0) { + byte[] packed; + if(hasIncompleteVersionstamp()) { + packed = packWithVersionstamp(null); + } + else { + packed = pack(); + } + memoizedHash = Arrays.hashCode(packed); + } + return memoizedHash; } /** @@ -781,8 +796,10 @@ public class Tuple implements Comparable, Iterable { public boolean equals(Object o) { if(o == null) return false; + if(o == this) + return true; if(o instanceof Tuple) { - return Arrays.equals(this.pack(), ((Tuple) o).pack()); + return compareTo((Tuple)o) == 0; } return false; }