[infinispan-commits] Infinispan SVN: r738 - in trunk/tree/src: test/java/org/infinispan/profiling/testinternals and 1 other directory.

infinispan-commits at lists.jboss.org infinispan-commits at lists.jboss.org
Wed Aug 26 08:44:21 EDT 2009


Author: manik.surtani at jboss.com
Date: 2009-08-26 08:44:21 -0400 (Wed, 26 Aug 2009)
New Revision: 738

Modified:
   trunk/tree/src/main/java/org/infinispan/tree/Fqn.java
   trunk/tree/src/test/java/org/infinispan/profiling/testinternals/FqnGenerator.java
Log:
[ISPN-169] (Improve the performance of Fqns by backing with an immutable array rather than a list)

Modified: trunk/tree/src/main/java/org/infinispan/tree/Fqn.java
===================================================================
--- trunk/tree/src/main/java/org/infinispan/tree/Fqn.java	2009-08-26 10:52:42 UTC (rev 737)
+++ trunk/tree/src/main/java/org/infinispan/tree/Fqn.java	2009-08-26 12:44:21 UTC (rev 738)
@@ -23,17 +23,14 @@
 
 
 import net.jcip.annotations.Immutable;
-
 import org.infinispan.marshall.Ids;
 import org.infinispan.marshall.Marshallable;
-import org.infinispan.util.Immutables;
+import org.infinispan.util.Util;
 
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 
 /**
@@ -89,9 +86,8 @@
     */
    public static final String SEPARATOR = "/";
 
-   protected List<Object> elements;
+   private final Object[] elements;
    private transient int hash_code = 0;
-   protected int size = 0;
 
    /**
     * Immutable root Fqn.
@@ -109,33 +105,31 @@
     * Public to satisfy Externalization.  // TODO: Remove this ctor as well as Externalization!!
     */
    public Fqn() {
-      elements = Collections.emptyList();
-      size = 0;
+      elements = new Object[]{};
    }
 
+   private Fqn(Object... elements) {
+      this.elements = elements;
+   }
+
    /**
     * If safe is false, Collections.unmodifiableList() is used to wrap the list passed in.  This is an optimisation so
     * Fqn.fromString(), probably the most frequently used factory method, doesn't end up needing to use the
     * unmodifiableList() since it creates the list internally.
     *
     * @param names List of names
-    * @param safe  whether this list is referenced externally (safe = false) or not (safe = true).
     */
-   @SuppressWarnings("unchecked")
-   private Fqn(List names, boolean safe) {
-      if (names != null) {
-         // if not safe make a defensive copy
-         elements = safe ? names : Immutables.immutableListCopy(names);
-         size = elements.size();
-      } else {
-         elements = Collections.emptyList();
-         size = 0;
-      }
+   private Fqn(List names) {
+      if (names != null)
+         elements = names.toArray();
+      else
+         elements = new Object[]{};
    }
 
-   private Fqn(Fqn base, List relative) {
-      elements = Immutables.immutableListMerge(base.elements, relative);
-      size = elements.size();
+   private Fqn(Fqn base, Object... relative) {
+      elements = new Object[base.elements.length + relative.length];
+      System.arraycopy(base.elements, 0, elements, 0, base.elements.length);
+      System.arraycopy(relative, 0, elements, base.elements.length, relative.length);
    }
 
    // ----------------- END: Private constructors for use by factory methods only. ----------------------
@@ -149,26 +143,10 @@
     */
    @SuppressWarnings("unchecked")
    public static Fqn fromList(List names) {
-      return new Fqn(names, false);
+      return new Fqn(names);
    }
 
    /**
-    * Retrieves an Fqn that represents the list of elements passed in.
-    *
-    * @param names list of elements that comprise the Fqn
-    * @param safe  if true, the list passed in is not defensively copied but used directly.  <b>Use with care.</b>  Make
-    *              sure you know what you are doing before you pass in a <tt>true</tt> value to <tt>safe</tt>, as it can
-    *              have adverse effects on performance or correctness.  The defensive copy of list elements is not just
-    *              for safety but also for performance as an appropriare List implementation is used, which works well
-    *              with Fqn operations.
-    * @return an Fqn
-    */
-   @SuppressWarnings("unchecked")
-   public static Fqn fromList(List names, boolean safe) {
-      return new Fqn(names, safe);
-   }
-
-   /**
     * Retrieves an Fqn that represents the array of elements passed in.
     *
     * @param elements array of elements that comprise the Fqn
@@ -176,7 +154,9 @@
     * @since 4.0
     */
    public static Fqn fromElements(Object... elements) {
-      return new Fqn(Arrays.asList(elements), true);
+      Object[] copy = new Object[elements.length];
+      System.arraycopy(elements, 0, copy, 0, elements.length);
+      return new Fqn(copy);
    }
 
    /**
@@ -200,7 +180,7 @@
     * @since 4.0
     */
    public static Fqn fromRelativeList(Fqn base, List relativeElements) {
-      return new Fqn(base, relativeElements);
+      return new Fqn(base, relativeElements.toArray());
    }
 
    /**
@@ -212,7 +192,7 @@
     * @since 4.0
     */
    public static Fqn fromRelativeElements(Fqn base, Object... relativeElements) {
-      return new Fqn(base, Arrays.asList(relativeElements));
+      return new Fqn(base, relativeElements);
    }
 
    /**
@@ -236,7 +216,7 @@
 
       String toMatch = stringRepresentation.startsWith(SEPARATOR) ? stringRepresentation.substring(1) : stringRepresentation;
       Object[] el = toMatch.split(SEPARATOR);
-      return new Fqn(Immutables.immutableListWrap(el), true);
+      return new Fqn(el);
    }
 
    /**
@@ -261,15 +241,18 @@
     * @return a subFqn
     */
    public Fqn getSubFqn(int startIndex, int endIndex) {
-      List el = elements.subList(startIndex, endIndex);
-      return new Fqn(el, true);
+      if (endIndex < startIndex) throw new IllegalArgumentException("End index cannot be less than the start index!");
+      int len = endIndex - startIndex;
+      Object[] el = new Object[len];
+      System.arraycopy(elements, startIndex, el, 0, len);
+      return new Fqn(el);
    }
 
    /**
     * @return the number of elements in the Fqn.  The root node contains zero.
     */
    public int size() {
-      return size;
+      return elements.length;
    }
 
    /**
@@ -277,7 +260,7 @@
     * @return Returns the nth element in the Fqn.
     */
    public Object get(int n) {
-      return elements.get(n);
+      return elements[n];
    }
 
    /**
@@ -286,7 +269,7 @@
     */
    public Object getLastElement() {
       if (isRoot()) return null;
-      return elements.get(size - 1);
+      return elements[elements.length - 1];
    }
 
    /**
@@ -294,9 +277,22 @@
     * @return true if the Fqn contains this element, false otherwise.
     */
    public boolean hasElement(Object element) {
-      return elements.indexOf(element) != -1;
+      return indexOf(element) != -1;
    }
 
+   private int indexOf(Object element) {
+      if (element == null) {
+         for (int i = 0; i < elements.length; i++) {
+            if (elements[i] == null) return i;
+         }
+      } else {
+         for (int i = 0; i < elements.length; i++) {
+            if (element.equals(elements[i])) return i;
+         }
+      }
+      return -1;
+   }
+
    /**
     * Returns true if obj is a Fqn with the same elements.
     */
@@ -309,7 +305,11 @@
          return false;
       }
       Fqn other = (Fqn) obj;
-      return size == other.size() && elements.equals(other.elements);
+      if (elements.length != other.elements.length) return false;
+      for (int i = elements.length - 1; i >= 0; i--) {
+         if (!Util.safeEquals(elements[i], other.elements[i])) return false;
+      }
+      return true;
    }
 
    /**
@@ -353,7 +353,7 @@
     * @return true if the target is a child of parentFqn
     */
    public boolean isChildOf(Fqn parentFqn) {
-      return parentFqn.size() != size && isChildOrEquals(parentFqn);
+      return parentFqn.elements.length != elements.length && isChildOrEquals(parentFqn);
    }
 
 
@@ -364,7 +364,7 @@
     * @return true if this is a direct child, false otherwise.
     */
    public boolean isDirectChildOf(Fqn parentFqn) {
-      return size == parentFqn.size() + 1 && isChildOf(parentFqn);
+      return elements.length == parentFqn.elements.length + 1 && isChildOf(parentFqn);
    }
 
    /**
@@ -381,14 +381,12 @@
     * @return true if this Fqn is equals or the child of parentFqn.
     */
    public boolean isChildOrEquals(Fqn parentFqn) {
-      List parentList = parentFqn.elements;
-      if (parentList.size() > size) {
+      Object[] parentEl = parentFqn.elements;
+      if (parentEl.length > elements.length) {
          return false;
       }
-      for (int i = parentList.size() - 1; i >= 0; i--) {
-         if (!parentList.get(i).equals(elements.get(i))) {
-            return false;
-         }
+      for (int i = parentEl.length - 1; i >= 0; i--) {
+         if (!Util.safeEquals(parentEl[i], elements[i])) return false;
       }
       return true;
    }
@@ -405,7 +403,7 @@
       return hashCode;
    }
 
-   protected String getStringRepresentation(List elements) {
+   protected String getStringRepresentation(Object[] elements) {
       StringBuilder builder = new StringBuilder();
       for (Object e : elements) {
          // incase user element 'e' does not implement equals() properly, don't rely on their implementation.
@@ -431,12 +429,12 @@
     * @return the parent Fqn
     */
    public Fqn getParent() {
-      switch (size) {
+      switch (elements.length) {
          case 0:
          case 1:
             return root();
          default:
-            return new Fqn(elements.subList(0, size - 1), true);
+            return getSubFqn(0, elements.length - 1);
       }
    }
 
@@ -451,7 +449,7 @@
     * @return true if the Fqn is Fqn.ROOT.
     */
    public boolean isRoot() {
-      return size == 0;
+      return elements.length == 0;
    }
 
    /**
@@ -478,7 +476,7 @@
     * @return an unmodifiable list
     */
    public List peekElements() {
-      return elements;
+      return Arrays.asList(elements);
    }
 
    /**
@@ -501,19 +499,19 @@
       Fqn subFqn = this.getSubFqn(oldAncestor.size(), size());
       return Fqn.fromRelativeFqn(newAncestor, subFqn);
    }
-   
+
    public static class Externalizer implements org.infinispan.marshall.Externalizer {
       public void writeObject(ObjectOutput output, Object object) throws IOException {
          Fqn fqn = (Fqn) object;
-         output.writeShort(fqn.size);
+         output.writeInt(fqn.elements.length);
          for (Object element : fqn.elements) output.writeObject(element);
       }
 
       public Object readObject(ObjectInput input) throws IOException, ClassNotFoundException {
-         short size = input.readShort();
-         List elements = new ArrayList(size);
-         for (int i = 0; i < size; i++) elements.add(input.readObject());
-         return Fqn.fromList(elements);
+         int size = input.readInt();
+         Object[] elements = new Object[size];
+         for (int i = 0; i < size; i++) elements[i] = input.readObject();
+         return new Fqn(elements);
       }
    }
 }
\ No newline at end of file

Modified: trunk/tree/src/test/java/org/infinispan/profiling/testinternals/FqnGenerator.java
===================================================================
--- trunk/tree/src/test/java/org/infinispan/profiling/testinternals/FqnGenerator.java	2009-08-26 10:52:42 UTC (rev 737)
+++ trunk/tree/src/test/java/org/infinispan/profiling/testinternals/FqnGenerator.java	2009-08-26 12:44:21 UTC (rev 738)
@@ -15,12 +15,12 @@
 
 public class FqnGenerator {
 
-   private static final Random r = new Random();   
+   private static final Random r = new Random();
 
    public static Fqn createRandomFqn(int depth) {
       List<String> fqnElements = new ArrayList<String>(depth);
       for (int i = 0; i < depth; i++) fqnElements.add(Integer.toHexString(r.nextInt(Integer.MAX_VALUE)));
-      return Fqn.fromList(fqnElements, true);
+      return Fqn.fromList(fqnElements);
    }
 
 



More information about the infinispan-commits mailing list