X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-reactor%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Fstmt%2Freactor%2FStatementContextBase.java;h=a9aa4099c3c1ac48d09962bb526a19b5a00153b2;hb=7f41bd0651d810544aa1359ce1d762a8185df016;hp=fa9f8a540d000a4da56536e855195724d6b69a2d;hpb=c87c92e768cc60fc0514aecfddf4841a6f5ad667;p=yangtools.git diff --git a/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java b/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java index fa9f8a540d..a9aa4099c3 100644 --- a/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java +++ b/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java @@ -44,7 +44,7 @@ import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; import org.opendaylight.yangtools.yang.model.api.meta.StatementSource; import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.ConfigStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.ConfigEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.DeviationStatement; import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement; import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier; @@ -69,7 +69,6 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils; import org.opendaylight.yangtools.yang.parser.spi.source.ImplicitSubstatement; import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; -import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference; import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace; import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace.SupportedFeatures; import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.KeyedValueAddedListener; @@ -141,7 +140,10 @@ public abstract class StatementContextBase, E private Multimap phaseListeners = ImmutableMultimap.of(); private Multimap phaseMutation = ImmutableMultimap.of(); + + // Note: this field is accessed either directly, or under substatementsInitialized == true private List> effective = ImmutableList.of(); + private List> effectOfStatement = ImmutableList.of(); private @Nullable ModelProcessingPhase completedPhase; @@ -155,13 +157,16 @@ public abstract class StatementContextBase, E // Flag for use with AbstractResumedStatement. This is hiding in the alignment shadow created by above boolean private boolean fullyDefined; + // Flag for InferredStatementContext. This is hiding in the alignment shadow created by above boolean. + private boolean substatementsInitialized; + // Flags for use with SubstatementContext. These are hiding in the alignment shadow created by above boolean and // hence improve memory layout. private byte flags; // SchemaPath cache for use with SubstatementContext and InferredStatementContext. This hurts RootStatementContext // a bit in terms of size -- but those are only a few and SchemaPath is on its way out anyway. - private volatile SchemaPath schemaPath; + private SchemaPath schemaPath; // Copy constructor used by subclasses to implement reparent() StatementContextBase(final StatementContextBase original) { @@ -343,7 +348,7 @@ public abstract class StatementContextBase, E */ @Override public final > void addToNs( - final Class type, final T key, final U value) { + final Class<@NonNull N> type, final T key, final U value) { addToNamespace(type, key, value); } @@ -363,13 +368,14 @@ public abstract class StatementContextBase, E * @throws NamespaceNotAvailableException when the namespace is not available. */ @Override - public final > V getFromNamespace(final Class type, - final T key) { + public final > V getFromNamespace( + final Class<@NonNull N> type, final T key) { return getBehaviourRegistry().getNamespaceBehaviour(type).getFrom(this, key); } @Override - public Collection> mutableEffectiveSubstatements() { + public final Collection> mutableEffectiveSubstatements() { + ensureEffectiveSubstatements(); if (effective instanceof ImmutableCollection) { return effective; } @@ -378,12 +384,15 @@ public abstract class StatementContextBase, E } private void shrinkEffective() { + // Initialization guarded by all callers if (effective.isEmpty()) { effective = ImmutableList.of(); } } - public void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef) { + // Note: has side-effect of ensureEffectiveSubstatements() + public final void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef) { + ensureEffectiveSubstatements(); if (effective.isEmpty()) { return; } @@ -411,10 +420,13 @@ public abstract class StatementContextBase, E * @param statementDef statement definition of the statement context to remove * @param statementArg statement argument of the statement context to remove */ - public void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef, + public final void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef, final String statementArg) { if (statementArg == null) { + // Note: has side-effect of ensureEffectiveSubstatements() removeStatementFromEffectiveSubstatements(statementDef); + } else { + ensureEffectiveSubstatements(); } if (effective.isEmpty()) { @@ -454,8 +466,9 @@ public abstract class StatementContextBase, E * @throws NullPointerException * if statement parameter is null */ - public void addEffectiveSubstatement(final Mutable substatement) { + public final void addEffectiveSubstatement(final Mutable substatement) { verifyStatement(substatement); + ensureEffectiveSubstatements(); beforeAddEffectiveStatement(1); final StatementContextBase stmt = (StatementContextBase) substatement; @@ -475,22 +488,49 @@ public abstract class StatementContextBase, E * @throws NullPointerException * if statement parameter is null */ - public void addEffectiveSubstatements(final Collection> statements) { + public final void addEffectiveSubstatements(final Collection> statements) { if (!statements.isEmpty()) { statements.forEach(StatementContextBase::verifyStatement); + ensureEffectiveSubstatements(); beforeAddEffectiveStatement(statements.size()); + doAddEffectiveSubstatements(statements); + } + } - final Collection> casted = - (Collection>) statements; - final ModelProcessingPhase phase = completedPhase; - if (phase != null) { - for (StatementContextBase stmt : casted) { - ensureCompletedPhase(stmt, phase); - } - } + // exposed for InferredStatementContext, which we expect to initialize effective substatements + void ensureEffectiveSubstatements() { + // No-op for everything except InferredStatementContext + } + + // Exposed for InferredStatementContextr only, others do not need initialization + Iterable> effectiveChildrenToComplete() { + return effective; + } + + // exposed for InferredStatementContext only + final void addInitialEffectiveSubstatements(final Collection> statements) { + verify(!substatementsInitialized, "Attempted to re-initialized statement {} with {}", this, statements); + substatementsInitialized = true; + + if (!statements.isEmpty()) { + statements.forEach(StatementContextBase::verifyStatement); + beforeAddEffectiveStatementUnsafe(statements.size()); + doAddEffectiveSubstatements(statements); + } + } - effective.addAll(casted); + private void doAddEffectiveSubstatements(final Collection> statements) { + final Collection> casted = + (Collection>) statements; + final ModelProcessingPhase phase = completedPhase; + if (phase != null) { + for (StatementContextBase stmt : casted) { + ensureCompletedPhase(stmt, phase); + } } + + // Initialization guarded by all callers + effective.addAll(casted); } // Make sure target statement has transitioned at least to specified phase. This method is just before we take @@ -507,29 +547,41 @@ public abstract class StatementContextBase, E private void beforeAddEffectiveStatement(final int toAdd) { // We cannot allow statement to be further mutated - final StatementSourceReference ref = getStatementSourceReference(); - verify(completedPhase != ModelProcessingPhase.EFFECTIVE_MODEL, "Cannot modify finished statement at %s", ref); + verify(completedPhase != ModelProcessingPhase.EFFECTIVE_MODEL, "Cannot modify finished statement at %s", + getStatementSourceReference()); + beforeAddEffectiveStatementUnsafe(toAdd); + } + private void beforeAddEffectiveStatementUnsafe(final int toAdd) { final ModelProcessingPhase inProgressPhase = getRoot().getSourceContext().getInProgressPhase(); checkState(inProgressPhase == ModelProcessingPhase.FULL_DECLARATION || inProgressPhase == ModelProcessingPhase.EFFECTIVE_MODEL, - "Effective statement cannot be added in declared phase at: %s", ref); + "Effective statement cannot be added in declared phase at: %s", getStatementSourceReference()); + // Initialization guarded by all callers if (effective.isEmpty()) { effective = new ArrayList<>(toAdd); } } - // Exists only due to memory optimization + // These two exists only due to memory optimization, should live in AbstractResumedStatement final boolean fullyDefined() { return fullyDefined; } - // Exists only due to memory optimization, should live in AbstractResumedStatement final void setFullyDefined() { fullyDefined = true; } + // These two exist only due to memory optimization, should live in InferredStatementContext + final boolean substatementsInitialized() { + return substatementsInitialized; + } + + final void setSubstatementsInitialized() { + substatementsInitialized = true; + } + @Override public E buildEffective() { final E existing; @@ -566,7 +618,7 @@ public abstract class StatementContextBase, E for (final StatementContextBase child : mutableDeclaredSubstatements()) { finished &= child.tryToCompletePhase(phase); } - for (final StatementContextBase child : effective) { + for (final StatementContextBase child : effectiveChildrenToComplete()) { finished &= child.tryToCompletePhase(phase); } return finished; @@ -591,13 +643,17 @@ public abstract class StatementContextBase, E if (openMutations.isEmpty()) { phaseMutation.removeAll(phase); - if (phaseMutation.isEmpty()) { - phaseMutation = ImmutableMultimap.of(); - } + cleanupPhaseMutation(); } return finished; } + private void cleanupPhaseMutation() { + if (phaseMutation.isEmpty()) { + phaseMutation = ImmutableMultimap.of(); + } + } + /** * Occurs on end of {@link ModelProcessingPhase} of source parsing. * @@ -774,10 +830,9 @@ public abstract class StatementContextBase, E /** * Adds a {@link ContextMutation} to a {@link ModelProcessingPhase}. * - * @throws IllegalStateException - * when the mutation was registered after phase was completed + * @throws IllegalStateException when the mutation was registered after phase was completed */ - void addMutation(final ModelProcessingPhase phase, final ContextMutation mutation) { + final void addMutation(final ModelProcessingPhase phase, final ContextMutation mutation) { ModelProcessingPhase finishedPhase = completedPhase; while (finishedPhase != null) { checkState(!phase.equals(finishedPhase), "Mutation registered after phase was completed at: %s", @@ -791,8 +846,15 @@ public abstract class StatementContextBase, E phaseMutation.put(phase, mutation); } + final void removeMutation(final ModelProcessingPhase phase, final ContextMutation mutation) { + if (!phaseMutation.isEmpty()) { + phaseMutation.remove(phase, mutation); + cleanupPhaseMutation(); + } + } + @Override - public > void addContext(final Class namespace, + public > void addContext(final Class<@NonNull N> namespace, final KT key,final StmtContext stmt) { addContextToNamespace(namespace, key, stmt); } @@ -913,6 +975,10 @@ public abstract class StatementContextBase, E */ abstract boolean hasEmptySubstatements(); + // Dual use method: AbstractResumedStatement does not use 'initialized' and InferredStatementContext ensures + // initialization. + // FIXME: 7.0.0: I think this warrants a separate subclasses, as InferredStatementContext wants to manage these + // itself. Before we do that, though, we need to analyze size impacts final boolean hasEmptyEffectiveSubstatements() { return effective.isEmpty(); } @@ -940,11 +1006,10 @@ public abstract class StatementContextBase, E return true; } - final StmtContext configStatement = StmtContextUtils.findFirstSubstatement(this, - ConfigStatement.class); final boolean isConfig; - if (configStatement != null) { - isConfig = configStatement.coerceStatementArgument(); + final Optional optConfig = findSubstatementArgument(ConfigEffectiveStatement.class); + if (optConfig.isPresent()) { + isConfig = optConfig.orElseThrow(); if (isConfig) { // Validity check: if parent is config=false this cannot be a config=true InferenceException.throwIf(!parent.isConfiguration(), getStatementSourceReference(), @@ -1006,22 +1071,16 @@ public abstract class StatementContextBase, E return false; } - // Exists only to support SubstatementContext/InferredStatementContext + // Exists only to support {SubstatementContext,InferredStatementContext}.getSchemaPath() + @Deprecated final @NonNull Optional substatementGetSchemaPath() { - SchemaPath local = schemaPath; - if (local == null) { - synchronized (this) { - local = schemaPath; - if (local == null) { - local = createSchemaPath(coerceParentContext()); - schemaPath = local; - } - } + if (schemaPath == null) { + schemaPath = createSchemaPath(coerceParentContext()); } - - return Optional.ofNullable(local); + return Optional.ofNullable(schemaPath); } + @Deprecated private SchemaPath createSchemaPath(final Mutable parent) { final Optional maybeParentPath = parent.getSchemaPath(); verify(maybeParentPath.isPresent(), "Parent %s does not have a SchemaPath", parent); @@ -1033,7 +1092,7 @@ public abstract class StatementContextBase, E final Object argument = getStatementArgument(); if (argument instanceof QName) { final QName qname = (QName) argument; - if (StmtContextUtils.producesDeclared(this, UsesStatement.class)) { + if (producesDeclared(UsesStatement.class)) { return maybeParentPath.orElse(null); } @@ -1046,11 +1105,10 @@ public abstract class StatementContextBase, E return parentPath.createChild(qname); } if (argument instanceof SchemaNodeIdentifier - && (StmtContextUtils.producesDeclared(this, AugmentStatement.class) - || StmtContextUtils.producesDeclared(this, RefineStatement.class) - || StmtContextUtils.producesDeclared(this, DeviationStatement.class))) { + && (producesDeclared(AugmentStatement.class) || producesDeclared(RefineStatement.class) + || producesDeclared(DeviationStatement.class))) { - return parentPath.createChild(((SchemaNodeIdentifier) argument).getPathFromRoot()); + return parentPath.createChild(((SchemaNodeIdentifier) argument).getNodeIdentifiers()); } // FIXME: this does not look right