Cache mismatched augmentations 25/77725/2
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 13 Nov 2018 14:13:41 +0000 (15:13 +0100)
committerRobert Varga <nite@hq.sk>
Wed, 21 Nov 2018 11:10:44 +0000 (11:10 +0000)
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 4ff423895fed4d94ddf613927b0c76f3278ce389..16a786f42fbca87a1c4777ca1e23567a73e15a48 100644 (file)
@@ -13,6 +13,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;
@@ -79,6 +80,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);
 
@@ -327,25 +330,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")