Cache mismatched augmentations 26/77726/1
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 13 Nov 2018 14:13:41 +0000 (15:13 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 13 Nov 2018 14:17:36 +0000 (15:17 +0100)
Address a FIXME around caching of mismatched augmentations, as it
seems openflowplugin is doing this on purpose.

The cache is expected to be needed infrequently in terms of associated
objects as well as modified infrequently, hence we use a space-efficient
ImmutableMap.

JIRA: MDSAL-388
Change-Id: Id86d8c713ee1014d9d4867558032ba3ccd51fc45
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
(cherry picked from commit c44477a41ca49f9fddf92b56a129f915741de5c7)

binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java

index 5ef88440759a682b18799f533eedcca125e258d0..637585a95048b84521cd82ec89752cc7636f1a85 100644 (file)
@@ -11,6 +11,7 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.collect.ImmutableSortedMap;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -74,6 +75,8 @@ abstract class DataObjectCodecContext<D extends DataObject, T extends DataNodeCo
             new ConcurrentHashMap<>();
     private final ConcurrentMap<Class<?>, DataContainerCodecPrototype<?>> byStreamAugmented = new ConcurrentHashMap<>();
 
+    private volatile ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> mismatchedAugmented = ImmutableMap.of();
+
     DataObjectCodecContext(final DataContainerCodecPrototype<T> prototype) {
         super(prototype);
 
@@ -281,25 +284,46 @@ abstract class DataObjectCodecContext<D extends DataObject, T extends DataNodeCo
         }
 
         /*
-         * It is potentially mismatched valid augmentation - we look up equivalent augmentation
-         * using reflection and walk all stream child and compare augmenations classes if they are
-         * equivalent.
-         *
-         * FIXME: Cache mapping of mismatched augmentation to real one, to speed up lookup.
+         * It is potentially mismatched valid augmentation - we look up equivalent augmentation using reflection
+         * and walk all stream child and compare augmentations classes if they are equivalent. When we find a match
+         * we'll cache it so we do not need to perform reflection operations again.
          */
+        final DataContainerCodecPrototype<?> mismatched = mismatchedAugmented.get(childClass);
+        if (mismatched != null) {
+            return mismatched;
+        }
+
         @SuppressWarnings("rawtypes")
         final Class<?> augTarget = BindingReflections.findAugmentationTarget((Class) childClass);
         if (getBindingClass().equals(augTarget)) {
             for (final DataContainerCodecPrototype<?> realChild : byStreamAugmented.values()) {
                 if (Augmentation.class.isAssignableFrom(realChild.getBindingClass())
                         && BindingReflections.isSubstitutionFor(childClass, realChild.getBindingClass())) {
-                    return realChild;
+                    return cacheMismatched(childClass, realChild);
                 }
             }
         }
         return null;
     }
 
+    private synchronized DataContainerCodecPrototype<?> cacheMismatched(final Class<?> childClass,
+            final DataContainerCodecPrototype<?> prototype) {
+        // Original access was unsynchronized, we need to perform additional checking
+        final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> local = mismatchedAugmented;
+        final DataContainerCodecPrototype<?> existing = local.get(childClass);
+        if (existing != null) {
+            return existing;
+        }
+
+        final Builder<Class<?>, DataContainerCodecPrototype<?>> builder = ImmutableMap.builderWithExpectedSize(
+            local.size() + 1);
+        builder.putAll(local);
+        builder.put(childClass, prototype);
+
+        mismatchedAugmented = builder.build();
+        return prototype;
+    }
+
     private DataContainerCodecPrototype<?> getAugmentationPrototype(final Type value) {
         final ClassLoadingStrategy loader = factory().getRuntimeContext().getStrategy();
         @SuppressWarnings("rawtypes")