Separate out StatementSupport.applyCopyPolicy() 53/94653/4
authorRobert Varga <robert.varga@pantheon.tech>
Sun, 17 Jan 2021 09:00:23 +0000 (10:00 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sun, 17 Jan 2021 13:36:19 +0000 (14:36 +0100)
We have two concerns here:
- copying statements for inference purposes and lazily instantiating
  them there
- creating EffectiveStatement copies.

StatementSupport.copyPolicy() and StatementContextBase.copyAsChildOf()
take care of the first part.

StatementSupport.effectiveCopyOf() and
StatementContextBase.asEffectiveChildOf() are responsible for the
second concern. For now they are not wired, but concentrate remaining
FIXMEs for direction we need to in.

JIRA: YANGTOOLS-1195
Change-Id: I3b0a63b4620cf933ce104dc37e9db8678c71aba5
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/InferredStatementContext.java
yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractStatementSupport.java
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ForwardingStatementSupport.java
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupport.java

index 1f062e62e66966cba7db8632ab5522abf9597475..fb691e3c319ed460947c4be3b48cc7d6528fdcbd 100644 (file)
@@ -376,6 +376,10 @@ final class InferredStatementContext<A, D extends DeclaredStatement<A>, E extend
     }
 
     private Optional<? extends Mutable<?, ?, ?>> copySubstatement(final Mutable<?, ?, ?> substatement) {
+        // FIXME: YANGTOOLS-1195: this is not exactly what we want to do here, because we are deling with two different
+        //                        requests: copy for inference purposes (this method), while we also copy for purposes
+        //                        of buildEffective() -- in which case we want to probably invoke asEffectiveChildOf()
+        //                        or similar
         return substatement.copyAsChildOf(this, childCopyType, targetModule);
     }
 
index 899345574ab9f99a4d4ccbd137ba599788e9861b..cd07b95b1cb51e30d3054050f5d6434d6234f96a 100644 (file)
@@ -597,23 +597,15 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         checkEffectiveModelCompleted(this);
 
         final StatementSupport<A, D, E> support = definition.support();
-        final CopyPolicy policy = support.applyCopyPolicy(this, parent, type, targetModule);
+        final CopyPolicy policy = support.copyPolicy();
         switch (policy) {
             case CONTEXT_INDEPENDENT:
-                if (hasEmptySubstatements()) {
-                    // This statement is context-independent and has no substatements -- hence it can be freely shared.
+                if (substatementsContextIndependent()) {
                     return Optional.of(replicaAsChildOf(parent));
                 }
-                // ascertaining substatements could be quite costly, let's just fall through to declared copy and deal
-                // shortcut it when we build the statements.
+
                 // fall through
             case DECLARED_COPY:
-                // FIXME: YANGTOOLS-694: this is still to eager, we really want to copy as a lazily-instantiated
-                //                       context, so that we can support building an effective statement without copying
-                //                       anything -- we will typically end up not being inferred against. In that case,
-                //                       this slim context should end up dealing with differences at buildContext()
-                //                       time. This is a YANGTOOLS-1067 prerequisite (which will deal with what can and
-                //                       cannot be shared across instances).
                 return Optional.of(parent.childCopyOf(this, type, targetModule));
             case IGNORE:
                 return Optional.empty();
@@ -624,6 +616,37 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         }
     }
 
+    private boolean substatementsContextIndependent() {
+        // FIXME: YANGTOOLS-1195: we really want to compute (and cache) the summary for substatements.
+        //
+        // For now we just check if there are any substatements, but we really want to ask:
+        //
+        //   Are all substatements (recursively) CONTEXT_INDEPENDENT as well?
+        //
+        // Which is something we want to compute once and store. This needs to be implemented.
+        return hasEmptySubstatements();
+    }
+
+    // FIXME: YANGTOOLS-1195: this method is unused, but should be called from InferredStatementContext at the very
+    //        least. It should return @NonNull -- either 'E' or EffectiveStmtCtx.Current'. Perhaps its arguments need
+    //        to be adjusted, too.
+    final void asEffectiveChildOf(final Mutable<?, ?, ?> parent, final CopyType type, final QNameModule targetModule) {
+        checkEffectiveModelCompleted(this);
+
+        final StatementSupport<A, D, E> support = definition.support();
+        final StmtContext<?, ?, ?> effective = support.effectiveCopyOf(this, parent, type, targetModule);
+        if (effective == this) {
+            LOG.debug("Should reuse {}", this);
+            return;
+        }
+
+        // FIXME: YANGTOOLS-1195: here is probably where we want to do some statement reuse: even if the parent is
+        //                        affected, some substatements may not -- in which case we want to reuse them. This
+        //                        probably needs to be a callout of some kind.
+        // FIXME: YANGTOOLS-1067: an incremental improvement to that is that if no substatements changed, we want to
+        //                        be reusing the entire List<EffectiveStatement> and pass that as substatements.
+    }
+
     @Override
     public final Mutable<?, ?, ?> childCopyOf(final StmtContext<?, ?, ?> stmt, final CopyType type,
             final QNameModule targetModule) {
index 4e11270681215ceedc40491054c5f8882554ebd5..0622463b8212cde180b5b7c2dfdcfef60eae35bc 100644 (file)
@@ -11,6 +11,7 @@ import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.Beta;
+import com.google.common.base.VerifyException;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.QNameModule;
@@ -46,11 +47,25 @@ public abstract class AbstractStatementSupport<A, D extends DeclaredStatement<A>
     }
 
     @Override
-    public CopyPolicy applyCopyPolicy(final Mutable<?, ?, ?> stmt, final Mutable<?, ?, ?> parent,
-            final CopyType copyType, final QNameModule targetModule) {
+    public final CopyPolicy copyPolicy() {
         return copyPolicy;
     }
 
+    @Override
+    public final StmtContext<?, ?, ?> effectiveCopyOf(final StmtContext<?, ?, ?> stmt, final Mutable<?, ?, ?> parent,
+            final CopyType copyType, final QNameModule targetModule) {
+        switch (copyPolicy) {
+            case CONTEXT_INDEPENDENT:
+                return stmt;
+            case DECLARED_COPY:
+                // FIXME: YANGTOOLS-1195: this is too harsh, we need to make a callout to subclass methods so they
+                //                        actually examine the differences.
+                return parent.childCopyOf(stmt, copyType, targetModule);
+            default:
+                throw new VerifyException("Attempted to apply " + copyPolicy);
+        }
+    }
+
     @Override
     public void onStatementAdded(final StmtContext.Mutable<A, D, E> stmt) {
         // NOOP for most implementations
index 1e8eca6b2c0d2c531824b32654abdfdbf54d2e8c..827a97bdc9488cab6ecce9e1d46f64ff70e463b0 100644 (file)
@@ -92,8 +92,13 @@ public abstract class ForwardingStatementSupport<A, D extends DeclaredStatement<
     }
 
     @Override
-    public CopyPolicy applyCopyPolicy(final Mutable<?, ?, ?> stmt, final Mutable<?, ?, ?> parent,
+    public CopyPolicy copyPolicy() {
+        return delegate().copyPolicy();
+    }
+
+    @Override
+    public StmtContext<?, ?, ?> effectiveCopyOf(final StmtContext<?, ?, ?> stmt, final Mutable<?, ?, ?> parent,
             final CopyType copyType, final QNameModule targetModule) {
-        return delegate().applyCopyPolicy(stmt, parent, copyType, targetModule);
+        return delegate().effectiveCopyOf(stmt, parent, copyType, targetModule);
     }
 }
index a1be785a6b22429bf4f31bd6bc4e23e01c4acb4d..419c28c60d216e644a1a0acdf1ba84614e6573ab 100644 (file)
@@ -141,7 +141,42 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
     @Nullable StatementSupport<?, ?, ?> getSupportSpecificForArgument(String argument);
 
     /**
-     * Determine reactor copy behavior of a statement instance. Statement support classes are required to determine
+     * Return this statement's {@link CopyPolicy}. This is a static value, reflecting how this statement reacts to being
+     * replicated to a different context, without reflecting on behaviour of potential substatements, which would come
+     * into play in something like:
+     *
+     * <pre>
+     *   <code>
+     *     module foo {
+     *       namespace foo;
+     *       prefix foo;
+     *
+     *       extension note {
+     *         argument string {
+     *           type string {
+     *             length 1..max;
+     *           }
+     *         }
+     *         description "Can be used in description/reference statements to attach additional notes";
+     *       }
+     *
+     *       description "A nice module extending description statement semantics" {
+     *         foo:note "We can now attach description/reference a note.";
+     *         foo:note "Also another note";
+     *       }
+     *     }
+     *   </code>
+     * </pre>
+     *
+     * <p>
+     * In this scenario, it is the reactor's job to figure out what to do (like talking to substatements).
+     *
+     * @return This statement's copy policy
+     */
+    @NonNull CopyPolicy copyPolicy();
+
+    /**
+     * Determine reactor copy behaviour of a statement instance. Statement support classes are required to determine
      * their operations with regard to their statements being replicated into different contexts, so that
      * {@link Mutable} instances are not created when it is evident they are superfluous.
      *
@@ -156,26 +191,17 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      *       the default namespace to parent's namespace, whereas {@code augment} does not.</li>
      * </ul>
      *
+     * <p>
+     * Implementations should return the context to use -- returning {@code stmt} if there is no change or a copy of it.
+     *
      * @param stmt Context of statement to be copied statement
      * @param parent Parent statement context
      * @param copyType Type of copy being performed
      * @param targetModule Target module, if present
-     * @return Policy that needs to be applied to the copy operation of this statement.
+     * @return StmtContext holding the effective state
      */
-    default @NonNull CopyPolicy applyCopyPolicy(final Mutable<?, ?, ?> stmt, final Mutable<?, ?, ?> parent,
-            final CopyType copyType, @Nullable final QNameModule targetModule) {
-        // Most of statement supports will just want to copy the statement
-        // FIXME: YANGTOOLS-694: that is not strictly true. Subclasses of this should indicate if they are themselves
-        //                       copy-sensitive:
-        //                       1) if they are not and cannot be targeted by inference, and all their current
-        //                          substatements are also non-sensitive, we want to return the same context.
-        //                       2) if they are not and their current substatements are sensitive, we want to copy
-        //                          as a lazily-instantiated interceptor to let it deal with substatements when needed
-        //                          (YANGTOOLS-1067 prerequisite)
-        //                       3) otherwise perform this eager copy
-        //      return Optional.of(parent.childCopyOf(stmt, copyType, targetModule));
-        return CopyPolicy.DECLARED_COPY;
-    }
+    @NonNull StmtContext<?, ?, ?> effectiveCopyOf(StmtContext<?, ?, ?> stmt, Mutable<?, ?, ?> parent, CopyType copyType,
+        @Nullable QNameModule targetModule);
 
     /**
      * Given a raw string representation of an argument, try to use a shared representation.
@@ -247,8 +273,7 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
     /**
      * Statement context copy policy, indicating how should reactor handle statement copy operations. Every statement
      * copied by the reactor is subject to policy check done by
-     * {@link StatementSupport#applyCopyPolicy(Mutable, Mutable, CopyType, QNameModule)}.
-     *
+     * {@link StatementSupport#effectiveCopyOf(StmtContext, Mutable, CopyType, QNameModule)}.
      */
     enum CopyPolicy {
         /**