Performance improvements to yang.data.api.InstanceIdentifier 84/5184/2
authorTony Tkacik <ttkacik@cisco.com>
Fri, 7 Feb 2014 21:04:16 +0000 (22:04 +0100)
committerTony Tkacik <ttkacik@cisco.com>
Fri, 7 Feb 2014 22:44:53 +0000 (23:44 +0100)
- Changed Collections.unmodifiableMap() to ImmutableMap,
  which is faster and safer, since the InstanceIdentifier
  contract requires immutability
- Added hashCode cache, which is safe, since all state
  captured by instance is immutable, from the moment of
  the object allocation.

Change-Id: I4d52af24f58c63ff5870e098b2b5fc9bbb34aec4
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/InstanceIdentifier.java

index b0cce8f2be844817c3b05edd57bb91680a8a9f88..79a7f4c31797d670ad0d650d2feae3b32fa718a4 100644 (file)
@@ -7,25 +7,25 @@
  */
 package org.opendaylight.yangtools.yang.data.api;\r
 \r
-import java.io.Serializable;\r
-import java.util.Collections;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-\r
-import org.opendaylight.yangtools.concepts.Builder;\r
-import org.opendaylight.yangtools.concepts.Immutable;\r
-import org.opendaylight.yangtools.concepts.Path;\r
-import org.opendaylight.yangtools.yang.common.QName;\r
-\r
-import com.google.common.collect.ImmutableList;\r
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.yang.common.QName;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 \r
 public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable, Serializable {\r
 \r
     private static final long serialVersionUID = 8467409862384206193L;\r
     private final List<PathArgument> path;\r
 \r
-    private transient String to_string_cache = null;\r
+    private transient String toStringCache = null;
+    private transient Integer hashCodeCache = null;\r
 \r
     public List<PathArgument> getPath() {\r
         return path;\r
@@ -40,27 +40,48 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
     }\r
 \r
     @Override\r
-    public int hashCode() {\r
-        final int prime = 31;\r
-        int result = 1;\r
-        result = prime * result + ((path == null) ? 0 : path.hashCode());\r
-        return result;\r
+    public int hashCode() {
+        /*
+         * The hashCodeCache is safe, since the object contract requires immutability
+         * of the object and all objects referenced from this object.
+         *
+         * Used lists, maps are immutable. Path Arguments (elements) are also immutable,
+         * since the PathArgument contract requires immutability.
+         *
+         * The cache is thread-safe - if multiple computations occurs at the same time,
+         * cache will be overwritten with same result.
+         */
+        if(hashCodeCache  == null) {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            hashCodeCache = result;
+        }
+        return hashCodeCache;\r
     }\r
 \r
     @Override\r
     public boolean equals(Object obj) {\r
-        if (this == obj)\r
+        if (this == obj) {\r
             return true;\r
-        if (obj == null)\r
-            return false;\r
-        if (getClass() != obj.getClass())\r
-            return false;\r
-        InstanceIdentifier other = (InstanceIdentifier) obj;\r
+        }
+        if (obj == null) {\r
+            return false;
+        }\r
+        if (getClass() != obj.getClass()) {\r
+            return false;
+        }\r
+        InstanceIdentifier other = (InstanceIdentifier) obj;
+        if(this.hashCode() != obj.hashCode()) {
+            return false;
+        }\r
         if (path == null) {\r
-            if (other.path != null)\r
-                return false;\r
-        } else if (!path.equals(other.path))\r
-            return false;\r
+            if (other.path != null) {\r
+                return false;
+            }\r
+        } else if (!path.equals(other.path)) {\r
+            return false;
+        }\r
         return true;\r
     }\r
 \r
@@ -97,7 +118,7 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
     public static final class NodeIdentifier implements PathArgument {\r
 \r
         /**\r
-         * \r
+         *\r
          */\r
         private static final long serialVersionUID = -2255888212390871347L;\r
 \r
@@ -107,6 +128,7 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
             this.nodeType = node;\r
         }\r
 \r
+        @Override
         public QName getNodeType() {\r
             return nodeType;\r
         }\r
@@ -145,7 +167,7 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
     public static final class NodeIdentifierWithPredicates implements PathArgument {\r
 \r
         /**\r
-         * \r
+         *\r
          */\r
         private static final long serialVersionUID = -4787195606494761540L;\r
 \r
@@ -154,12 +176,12 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
 \r
         public NodeIdentifierWithPredicates(QName node, Map<QName, Object> keyValues) {\r
             this.nodeType = node;\r
-            this.keyValues = Collections.unmodifiableMap(new HashMap<QName, Object>(keyValues));\r
+            this.keyValues = ImmutableMap.copyOf(keyValues);\r
         }\r
 \r
         public NodeIdentifierWithPredicates(QName node, QName key, Object value) {\r
             this.nodeType = node;\r
-            this.keyValues = Collections.singletonMap(key, value);\r
+            this.keyValues = ImmutableMap.of(key, value);\r
         }\r
 \r
         @Override\r
@@ -211,7 +233,7 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
     public static final class NodeWithValue implements PathArgument {
 
         /**
-         * 
+         *
          */
         private static final long serialVersionUID = -3637456085341738431L;
 
@@ -272,7 +294,7 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
 \r
     private static class BuilderImpl implements InstanceIdentifierBuilder {\r
 \r
-        private final ImmutableList.Builder<PathArgument> path; \r
+        private final ImmutableList.Builder<PathArgument> path;\r
 \r
         public BuilderImpl() {\r
             path = ImmutableList.<PathArgument>builder();\r
@@ -331,17 +353,27 @@ public class InstanceIdentifier implements Path<InstanceIdentifier>, Immutable,
     }\r
 \r
     @Override\r
-    public String toString() {\r
-        if (to_string_cache != null) {\r
-            return to_string_cache;\r
+    public String toString() {
+        /*
+         * The toStringCache is safe, since the object contract requires immutability
+         * of the object and all objects referenced from this object.
+         *
+         * Used lists, maps are immutable. Path Arguments (elements) are also immutable,
+         * since the PathArgument contract requires immutability.
+         *
+         * The cache is thread-safe - if multiple computations occurs at the same time,
+         * cache will be overwritten with same result.
+         */\r
+        if (toStringCache != null) {\r
+            return toStringCache;\r
         }\r
         StringBuilder builder = new StringBuilder();\r
         for (PathArgument argument : path) {\r
             builder.append("/");\r
             builder.append(argument.toString());\r
         }\r
-        to_string_cache = builder.toString();\r
-        return to_string_cache;\r
+        toStringCache = builder.toString();\r
+        return toStringCache;\r
     }\r
 \r
     public static InstanceIdentifierBuilder builder(QName node) {\r