Shortcut access to global NamespaceStorage 50/94650/15
authorRobert Varga <robert.varga@pantheon.tech>
Thu, 6 Apr 2023 12:54:28 +0000 (14:54 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Thu, 6 Apr 2023 15:04:57 +0000 (17:04 +0200)
Most of our namespaces are stored in StorageType.GLOBAL. Accessing that
requires walking the NamespaceStorage tree completely towards its root,
which takes a lot of time.

This is highlighted by the fact that yang-parser-reactor already
performs this walk in order to find the actual behaviour, which is
stored in BuildGlobalContext -- which happens to also be the GLOBAL
NamespaceStorage object.

The result of that walk is NamespaceAccess, which is always instantiated
from a place which has immediate access to BuildGlobalContext -- either
it is BuildGlobalContext itself or it is SourceSpecificContext.

This patch introduces NamespaceBehaviour.GlobalStorageAccess, which
allows users to acquire the global NamespaceStorage and modifies
NamespaceBehaviour methods to require an instance of this interface.

NamespaceAccesss is extended to implement GlobalStorageAccess and taught
to pass itself to the backing NamespaceBehaviour.

JIRA: YANGTOOLS-1497
Change-Id: I74ac1a31176e8f3fc33875dff775965d1129391f
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
parser/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/BehaviourNamespaceAccess.java
parser/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/BuildGlobalContext.java
parser/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SimpleNamespaceContext.java
parser/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/VirtualNamespaceContext.java
parser/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/SchemaTreeNamespaceBehaviour.java
parser/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/DerivedNamespaceBehaviour.java
parser/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceBehaviour.java
parser/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceStorage.java

index 1715d18a094c1d8ce5a4d651981c50ead4c7356a..5575912e45a01b8ea75aaab4fcaf72957d5f9d32 100644 (file)
@@ -14,28 +14,35 @@ import java.util.Map;
 import java.util.Map.Entry;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.GlobalStorageAccess;
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceKeyCriterion;
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceStorage;
 
 /**
- * A {@link NamespaceAccess} backed by a {@link NamespaceBehaviour}.
- *
+ * A {@link NamespaceAccess} backed by a {@link NamespaceBehaviour}. Also holds reference to {@link BuildGlobalContext}.
  */
-abstract class BehaviourNamespaceAccess<K, V> extends NamespaceAccess<K, V> {
+abstract class BehaviourNamespaceAccess<K, V> extends NamespaceAccess<K, V> implements GlobalStorageAccess {
+    private final @NonNull AbstractNamespaceStorage globalContext;
     private final @NonNull NamespaceBehaviour<K, V> behaviour;
 
-    BehaviourNamespaceAccess(final NamespaceBehaviour<K, V> behaviour) {
+    BehaviourNamespaceAccess(final AbstractNamespaceStorage globalContext, final NamespaceBehaviour<K, V> behaviour) {
+        this.globalContext = requireNonNull(globalContext);
         this.behaviour = requireNonNull(behaviour);
     }
 
+    @Override
+    public final AbstractNamespaceStorage getGlobalStorage() {
+        return globalContext;
+    }
+
     @Override
     final V valueFrom(final NamespaceStorage storage, final K key) {
-        return behaviour.getFrom(storage, key);
+        return behaviour.getFrom(this, storage, key);
     }
 
     @Override
     final void valueTo(final NamespaceStorage storage, final K key, final V value) {
-        behaviour.addTo(storage, key, value);
+        behaviour.addTo(this, storage, key, value);
         onValueTo(storage, key, value);
     }
 
@@ -43,12 +50,12 @@ abstract class BehaviourNamespaceAccess<K, V> extends NamespaceAccess<K, V> {
 
     @Override
     final Map<K, V> allFrom(final NamespaceStorage storage) {
-        return behaviour.getAllFrom(storage);
+        return behaviour.getAllFrom(this, storage);
     }
 
     @Override
     final Entry<K, V> entryFrom(final NamespaceStorage storage, final NamespaceKeyCriterion<K> criterion) {
-        return behaviour.getFrom(storage, criterion);
+        return behaviour.getFrom(this, storage, criterion);
     }
 
     @Override
index 259fe129bf8cd7eba9d5b7bbd50e9dcbf38904c7..32ce8cbc5dd8b1ac471f5bddfc4d91d5ad117549 100644 (file)
@@ -152,11 +152,11 @@ final class BuildGlobalContext extends AbstractNamespaceStorage {
     @SuppressWarnings({ "unchecked", "rawtypes" })
     private <K, V> @NonNull NamespaceAccess<K, V> createNamespaceContext(final NamespaceBehaviour<K, V> behaviour) {
         if (behaviour instanceof DerivedNamespaceBehaviour derived) {
-            final VirtualNamespaceContext derivedContext = new VirtualNamespaceContext(derived);
+            final VirtualNamespaceContext derivedContext = new VirtualNamespaceContext(this, derived);
             accessNamespace(derived.getDerivedFrom()).addDerivedNamespace(derivedContext);
             return derivedContext;
         }
-        return new SimpleNamespaceContext<>(behaviour);
+        return new SimpleNamespaceContext<>(this, behaviour);
     }
 
     StatementDefinitionContext<?, ?, ?> getStatementDefinition(final YangVersion version, final QName name) {
index 4c5f6dc7c7f9559224600d1eae66b91fcf8a9317..ce1160ab73ee624290b4e87e388e42e48ebcb452 100644 (file)
@@ -20,8 +20,8 @@ final class SimpleNamespaceContext<K, V> extends BehaviourNamespaceAccess<K, V>
 
     private Collection<PredicateValueAddedListener<K, V>> predicateListeners;
 
-    SimpleNamespaceContext(final NamespaceBehaviour<K, V> behaviour) {
-        super(behaviour);
+    SimpleNamespaceContext(final AbstractNamespaceStorage globalContext, final NamespaceBehaviour<K, V> behaviour) {
+        super(globalContext, behaviour);
     }
 
     @Override
index 3af073ec2c068e8cb5c0dbb654b54b0c31eecbcd..e6304b7d351250cd11ed264c6cea58b89edf4caa 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.parser.stmt.reactor;
 
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 import org.opendaylight.yangtools.yang.parser.spi.meta.DerivedNamespaceBehaviour;
@@ -16,9 +18,10 @@ final class VirtualNamespaceContext<K, V, D> extends BehaviourNamespaceAccess<K,
     private final Multimap<D, KeyedValueAddedListener<K>> listeners = HashMultimap.create();
     private final DerivedNamespaceBehaviour<K, V, D, ?> derivedDelegate;
 
-    VirtualNamespaceContext(final DerivedNamespaceBehaviour<K, V, D, ?> behaviour) {
-        super(behaviour);
-        derivedDelegate = behaviour;
+    VirtualNamespaceContext(final AbstractNamespaceStorage globalContext,
+            final DerivedNamespaceBehaviour<K, V, D, ?> behaviour) {
+        super(globalContext, behaviour);
+        derivedDelegate = requireNonNull(behaviour);
     }
 
     @Override
index 54e4dbdf6770cef0ebd2e45e1795a90109ff70f9..8cca66f30ac222d7e1431665b8491bffcb1aec6c 100644 (file)
@@ -40,7 +40,8 @@ final class SchemaTreeNamespaceBehaviour<D extends DeclaredStatement<QName>, E e
      * This method is analogous to {@link SchemaTreeAwareEffectiveStatement#findSchemaTreeNode(QName)}.
      */
     @Override
-    public StmtContext<QName, D, E> getFrom(final NamespaceStorage storage, final QName key) {
+    public StmtContext<QName, D, E> getFrom(final GlobalStorageAccess globalAccess, final NamespaceStorage storage,
+            final QName key) {
         // Get the backing storage node for the requested storage
         final NamespaceStorage storageNode = globalOrStatementSpecific(storage);
         // Check try to look up existing node
@@ -51,13 +52,15 @@ final class SchemaTreeNamespaceBehaviour<D extends DeclaredStatement<QName>, E e
     }
 
     @Override
-    public Map<QName, StmtContext<QName, D, E>> getAllFrom(final NamespaceStorage storage) {
+    public Map<QName, StmtContext<QName, D, E>> getAllFrom(final GlobalStorageAccess globalAccess,
+            final NamespaceStorage storage) {
         // FIXME: 7.0.0: this method needs to be well-defined
         return null;
     }
 
     @Override
-    public void addTo(final NamespaceStorage storage, final QName key, final StmtContext<QName, D, E> value) {
+    public void addTo(final GlobalStorageAccess globalAccess, final NamespaceStorage storage, final QName key,
+            final StmtContext<QName, D, E> value) {
         final var prev = globalOrStatementSpecific(storage).putToLocalStorageIfAbsent(namespace(), key, value);
         if (prev != null) {
             throw new SourceException(value,
index 6b76cc1e7b84f81a453ce2178475632dcf3f240f..40aa5f18f1d8346142b62d193b0f4bff87f8e6f6 100644 (file)
@@ -36,15 +36,16 @@ public abstract class DerivedNamespaceBehaviour<K, V, L, O extends ParserNamespa
     }
 
     @Override
-    public Map<K, V> getAllFrom(final NamespaceStorage storage) {
+    public Map<K, V> getAllFrom(final GlobalStorageAccess globalAccess, final NamespaceStorage storage) {
         throw new UnsupportedOperationException("Virtual namespaces does not support provision of all items.");
     }
 
     @Override
-    public abstract V getFrom(NamespaceStorage storage, K key);
+    public abstract V getFrom(GlobalStorageAccess globalAccess, NamespaceStorage storage, K key);
 
     @Override
-    public void addTo(final NamespaceStorage storage, final K key, final V value) {
+    public void addTo(final GlobalStorageAccess globalAccess, final NamespaceStorage storage, final K key,
+            final V value) {
         // Intentional noop
     }
 
index 6d03452f39c23d393e1757392fe405e7fea86ae2..d555e7deecd31cfd8c2efbdbeb5e7466a4911c79 100644 (file)
@@ -30,6 +30,18 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceStorage.StorageT
  * @param <V> Value type
  */
 public abstract class NamespaceBehaviour<K, V> {
+    /**
+     * Interface allowing quick access to {@link StorageType#GLOBAL} {@link NamespaceStorage}.
+     */
+    public interface GlobalStorageAccess {
+        /**
+         * Return the {@link StorageType#GLOBAL} {@link NamespaceStorage}.
+         *
+         * @return Global namespace storage
+         */
+        @NonNull NamespaceStorage getGlobalStorage();
+    }
+
     private final @NonNull ParserNamespace<K, V> namespace;
 
     protected NamespaceBehaviour(final ParserNamespace<K, V> namespace) {
@@ -50,7 +62,7 @@ public abstract class NamespaceBehaviour<K, V> {
      * @return global namespace behaviour for supplied namespace type.
      */
     public static <K, V> @NonNull NamespaceBehaviour<K, V> global(final ParserNamespace<K, V> namespace) {
-        return new StorageSpecific<>(namespace, StorageType.GLOBAL);
+        return new Global<>(namespace);
     }
 
     /**
@@ -101,22 +113,24 @@ public abstract class NamespaceBehaviour<K, V> {
     /**
      * Returns a value from model namespace storage according to key param class.
      *
+     * @param globalAccess A {@link GlobalStorageAccess}
      * @param storage namespace storage
      * @param key type parameter
      * @return value from model namespace storage according to key param class
      */
-    public abstract V getFrom(NamespaceStorage storage, K key);
+    public abstract V getFrom(GlobalStorageAccess globalAccess, NamespaceStorage storage, K key);
 
     /**
      * Returns the key/value mapping best matching specified criterion.
      *
+     * @param globalAccess A {@link GlobalStorageAccess}
      * @param storage namespace storage
      * @param criterion selection criterion
      * @return Selected mapping, if available.
      */
-    public final @Nullable Entry<K, V> getFrom(final NamespaceStorage storage,
+    public final @Nullable Entry<K, V> getFrom(final GlobalStorageAccess globalAccess, final NamespaceStorage storage,
             final NamespaceKeyCriterion<K> criterion) {
-        final var mappings = getAllFrom(storage);
+        final var mappings = getAllFrom(globalAccess, storage);
         if (mappings == null) {
             return null;
         }
@@ -145,19 +159,21 @@ public abstract class NamespaceBehaviour<K, V> {
     /**
      * Returns all values of a keys of param class from model namespace storage.
      *
+     * @param globalAccess A {@link GlobalStorageAccess}
      * @param storage namespace storage
      * @return all values of keys of param class from model namespace storage
      */
-    public abstract Map<K, V> getAllFrom(NamespaceStorage storage);
+    public abstract Map<K, V> getAllFrom(GlobalStorageAccess globalAccess, NamespaceStorage storage);
 
     /**
      * Adds a key/value to corresponding namespace storage according to param class.
      *
+     * @param globalAccess A {@link GlobalStorageAccess}
      * @param storage namespace storage
      * @param key type parameter
      * @param value type parameter
      */
-    public abstract void addTo(NamespaceStorage storage, K key, V value);
+    public abstract void addTo(GlobalStorageAccess globalAccess, NamespaceStorage storage, K key, V value);
 
     protected final V getFromLocalStorage(final NamespaceStorage storage, final K key) {
         return storage.getFromLocalStorage(namespace, key);
@@ -186,21 +202,22 @@ public abstract class NamespaceBehaviour<K, V> {
         }
 
         @Override
-        public final V getFrom(final NamespaceStorage storage, final K key) {
-            return getFromLocalStorage(findStorage(storage), key);
+        public final V getFrom(final GlobalStorageAccess globalAccess, final NamespaceStorage storage, final K key) {
+            return getFromLocalStorage(findStorage(globalAccess, storage), key);
         }
 
         @Override
-        public final Map<K, V> getAllFrom(final NamespaceStorage storage) {
-            return getAllFromLocalStorage(findStorage(storage));
+        public final Map<K, V> getAllFrom(final GlobalStorageAccess globalAccess, final NamespaceStorage storage) {
+            return getAllFromLocalStorage(findStorage(globalAccess, storage));
         }
 
         @Override
-        public final void addTo(final NamespaceStorage storage, final K key, final V value) {
-            addToStorage(findStorage(storage), key, value);
+        public final void addTo(final GlobalStorageAccess globalAccess, final NamespaceStorage storage, final K key,
+                final V value) {
+            addToStorage(findStorage(globalAccess, storage), key, value);
         }
 
-        abstract NamespaceStorage findStorage(NamespaceStorage storage);
+        abstract NamespaceStorage findStorage(GlobalStorageAccess globalAccess, NamespaceStorage storage);
     }
 
     private static final class StatementLocal<K, V> extends AbstractSpecific<K, V> {
@@ -209,11 +226,22 @@ public abstract class NamespaceBehaviour<K, V> {
         }
 
         @Override
-        NamespaceStorage findStorage(final NamespaceStorage storage) {
+        NamespaceStorage findStorage(final GlobalStorageAccess globalAccess, final NamespaceStorage storage) {
             return storage;
         }
     }
 
+    private static final class Global<K, V> extends AbstractSpecific<K, V> {
+        Global(final ParserNamespace<K, V> namespace) {
+            super(namespace);
+        }
+
+        @Override
+        NamespaceStorage findStorage(final GlobalStorageAccess globalAccess, final NamespaceStorage storage) {
+            return globalAccess.getGlobalStorage();
+        }
+    }
+
     private static final class StorageSpecific<K, V> extends AbstractSpecific<K, V> {
         private final StorageType type;
 
@@ -223,7 +251,7 @@ public abstract class NamespaceBehaviour<K, V> {
         }
 
         @Override
-        NamespaceStorage findStorage(final NamespaceStorage storage) {
+        NamespaceStorage findStorage(final GlobalStorageAccess globalAccess, final NamespaceStorage storage) {
             var current = storage;
             while (current != null && current.getStorageType() != type) {
                 current = current.getParentStorage();
@@ -243,7 +271,7 @@ public abstract class NamespaceBehaviour<K, V> {
         }
 
         @Override
-        public V getFrom(final NamespaceStorage storage, final K key) {
+        public V getFrom(final GlobalStorageAccess globalAccess, final NamespaceStorage storage, final K key) {
             NamespaceStorage current = storage;
             while (current != null) {
                 final V val = getFromLocalStorage(current, key);
@@ -256,7 +284,7 @@ public abstract class NamespaceBehaviour<K, V> {
         }
 
         @Override
-        public Map<K, V> getAllFrom(final NamespaceStorage storage) {
+        public Map<K, V> getAllFrom(final GlobalStorageAccess globalAccess, final NamespaceStorage storage) {
             var current = storage;
             while (current != null) {
                 final Map<K, V> val = getAllFromLocalStorage(current);
@@ -269,7 +297,8 @@ public abstract class NamespaceBehaviour<K, V> {
         }
 
         @Override
-        public void addTo(final NamespaceStorage storage, final K key, final V value) {
+        public void addTo(final GlobalStorageAccess globalAccess, final NamespaceStorage storage, final K key,
+                final V value) {
             addToStorage(storage, key, value);
         }
     }
index 4cce1963dc8cb47045e477d322552f56766de5d0..bc1492b69992f080c1459a81f149984b1fb5637b 100644 (file)
@@ -21,7 +21,8 @@ public interface NamespaceStorage {
      */
     enum StorageType {
         /**
-         * Global storage, visible from all sources.
+         * Global storage, visible from all sources. There is exactly one such storage in any {@link NamespaceStorage}
+         * hierarchy and it logically sits on top of it.
          */
         GLOBAL,
         /**
@@ -46,6 +47,12 @@ public interface NamespaceStorage {
      */
     @NonNull StorageType getStorageType();
 
+    /**
+     * Return the parent {@link NamespaceStorage}. If this storage is {@link StorageType#GLOBAL}, this method will
+     * return {@code null}.
+     *
+     * @return Parent storage, if this is not the global storage
+     */
     @Nullable NamespaceStorage getParentStorage();
 
     <K, V> @Nullable V getFromLocalStorage(ParserNamespace<K, V> type, K key);