BUG-650: Use lazy set in YangInstanceIdentifier/SchemaPath caches 28/11128/2
authorRobert Varga <rovarga@cisco.com>
Fri, 12 Sep 2014 22:32:04 +0000 (00:32 +0200)
committerTony Tkacik <ttkacik@cisco.com>
Sat, 13 Sep 2014 15:06:45 +0000 (15:06 +0000)
These cached values are just derived from immutable state, so we do not
need to force them to be visible by other threads -- they can calculate
them on their own and at some point one of the versions wins.

Change-Id: I3ecf272d151c693ef3adc519c33a065aa9dba94b
Signed-off-by: Robert Varga <rovarga@cisco.com>
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/YangInstanceIdentifier.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaPath.java

index 84ebdf0f2035f30446e0098220050a80e9e7399d..2916b88e8bfde2898622e3076b151f5e0b8421c5 100644 (file)
@@ -13,7 +13,6 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
-
 import java.io.Serializable;
 import java.lang.reflect.Array;
 import java.util.ArrayList;
@@ -25,7 +24,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
-
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 import org.opendaylight.yangtools.concepts.Builder;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.concepts.Path;
@@ -67,6 +66,11 @@ import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
  * @see http://tools.ietf.org/html/rfc6020#section-9.13
  */
 public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier>, Immutable, Serializable {
+    @SuppressWarnings("rawtypes")
+    private static final AtomicReferenceFieldUpdater<YangInstanceIdentifier, ImmutableList> LEGACYPATH_UPDATER =
+            AtomicReferenceFieldUpdater.newUpdater(YangInstanceIdentifier.class, ImmutableList.class, "legacyPath");
+    private static final AtomicReferenceFieldUpdater<YangInstanceIdentifier, String> TOSTRINGCACHE_UPDATER =
+            AtomicReferenceFieldUpdater.newUpdater(YangInstanceIdentifier.class, String.class, "toStringCache");
     private static final YangInstanceIdentifier EMPTY = trustedCreate(Collections.<PathArgument>emptyList());
 
     private static final long serialVersionUID = 2L;
@@ -80,11 +84,10 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
         // Temporary variable saves a volatile read
         ImmutableList<PathArgument> ret = legacyPath;
         if (ret == null) {
-            synchronized (this) {
-                // We could have used a synchronized block, but let's just not bother
-                ret = ImmutableList.copyOf(pathArguments);
-                legacyPath = ret;
-            }
+            // We could have used a synchronized block, but the window is quite
+            // small and worst that can happen is duplicate object construction.
+            ret = ImmutableList.copyOf(pathArguments);
+            LEGACYPATH_UPDATER.lazySet(this, ret);
         }
 
         return ret;
@@ -354,6 +357,8 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
     }
 
     private static abstract class AbstractPathArgument implements PathArgument {
+        private static final AtomicReferenceFieldUpdater<AbstractPathArgument, Integer> HASH_UPDATER =
+                AtomicReferenceFieldUpdater.newUpdater(AbstractPathArgument.class, Integer.class, "hash");
         private static final long serialVersionUID = -4546547994250849340L;
         private final QName nodeType;
         private volatile transient Integer hash = null;
@@ -380,13 +385,8 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
         public final int hashCode() {
             Integer ret = hash;
             if (ret == null) {
-                synchronized (this) {
-                    ret = hash;
-                    if (ret == null) {
-                        ret = hashCodeImpl();
-                        hash = ret;
-                    }
-                }
+                ret = hashCodeImpl();
+                HASH_UPDATER.lazySet(this, ret);
             }
 
             return ret;
@@ -787,23 +787,18 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
          */
         String ret = toStringCache;
         if (ret == null) {
-            synchronized (this) {
-                ret = toStringCache;
-                if (ret == null) {
-                    final StringBuilder builder = new StringBuilder("/");
-                    PathArgument prev = null;
-                    for (PathArgument argument : getPathArguments()) {
-                        if (prev != null) {
-                            builder.append('/');
-                        }
-                        builder.append(argument.toRelativeString(prev));
-                        prev = argument;
-                    }
-
-                    ret = builder.toString();
-                    toStringCache = ret;
+            final StringBuilder builder = new StringBuilder("/");
+            PathArgument prev = null;
+            for (PathArgument argument : getPathArguments()) {
+                if (prev != null) {
+                    builder.append('/');
                 }
+                builder.append(argument.toRelativeString(prev));
+                prev = argument;
             }
+
+            ret = builder.toString();
+            TOSTRINGCACHE_UPDATER.lazySet(this, ret);
         }
         return ret;
     }
index 56d240aed1ac426e4fd8ebd30ca4e87a9e09f446..b9f26f1b63a5986132cd7eef5da59553e6ad89dc 100644 (file)
@@ -12,12 +12,11 @@ import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
-
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
-
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.common.QName;
 
@@ -63,6 +62,10 @@ public abstract class SchemaPath implements Immutable {
         }
     }
 
+    @SuppressWarnings("rawtypes")
+    private static final AtomicReferenceFieldUpdater<SchemaPath, ImmutableList> LEGACYPATH_UPDATER =
+            AtomicReferenceFieldUpdater.newUpdater(SchemaPath.class, ImmutableList.class, "legacyPath");
+
     /**
      * Shared instance of the conceptual root schema node.
      */
@@ -97,13 +100,8 @@ public abstract class SchemaPath implements Immutable {
     private ImmutableList<QName> getLegacyPath() {
         ImmutableList<QName> ret = legacyPath;
         if (ret == null) {
-            synchronized (this) {
-                ret = legacyPath;
-                if (ret == null) {
-                    ret = ImmutableList.copyOf(getPathTowardsRoot()).reverse();
-                    legacyPath = ret;
-                }
-            }
+            ret = ImmutableList.copyOf(getPathTowardsRoot()).reverse();
+            LEGACYPATH_UPDATER.lazySet(this, ret);
         }
 
         return ret;