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;
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;
private Multimap<ModelProcessingPhase, OnPhaseFinished> phaseListeners = ImmutableMultimap.of();
private Multimap<ModelProcessingPhase, ContextMutation> phaseMutation = ImmutableMultimap.of();
+
+ // Note: this field is accessed either directly, or under substatementsInitialized == true
private List<StatementContextBase<?, ?, ?>> effective = ImmutableList.of();
+
private List<StmtContext<?, ?, ?>> effectOfStatement = ImmutableList.of();
private @Nullable ModelProcessingPhase completedPhase;
// 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<A, D, E> original) {
}
@Override
- public Collection<? extends Mutable<?, ?, ?>> mutableEffectiveSubstatements() {
+ public final Collection<? extends Mutable<?, ?, ?>> mutableEffectiveSubstatements() {
+ ensureEffectiveSubstatements();
if (effective instanceof ImmutableCollection) {
return effective;
}
}
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;
}
* @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()) {
* @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;
* @throws NullPointerException
* if statement parameter is null
*/
- public void addEffectiveSubstatements(final Collection<? extends Mutable<?, ?, ?>> statements) {
+ public final void addEffectiveSubstatements(final Collection<? extends Mutable<?, ?, ?>> statements) {
if (!statements.isEmpty()) {
statements.forEach(StatementContextBase::verifyStatement);
+ ensureEffectiveSubstatements();
beforeAddEffectiveStatement(statements.size());
+ doAddEffectiveSubstatements(statements);
+ }
+ }
- final Collection<? extends StatementContextBase<?, ?, ?>> casted =
- (Collection<? extends StatementContextBase<?, ?, ?>>) 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
+ }
- effective.addAll(casted);
+ // Exposed for InferredStatementContextr only, others do not need initialization
+ Iterable<StatementContextBase<?, ?, ?>> effectiveChildrenToComplete() {
+ return effective;
+ }
+
+ // exposed for InferredStatementContext only
+ final void addInitialEffectiveSubstatements(final Collection<? extends Mutable<?, ?, ?>> 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);
+ }
+ }
+
+ private void doAddEffectiveSubstatements(final Collection<? extends Mutable<?, ?, ?>> statements) {
+ final Collection<? extends StatementContextBase<?, ?, ?>> casted =
+ (Collection<? extends StatementContextBase<?, ?, ?>>) 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
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;
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;
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.
*
/**
* 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",
phaseMutation.put(phase, mutation);
}
+ final void removeMutation(final ModelProcessingPhase phase, final ContextMutation mutation) {
+ if (!phaseMutation.isEmpty()) {
+ phaseMutation.remove(phase, mutation);
+ cleanupPhaseMutation();
+ }
+ }
+
@Override
public <K, KT extends K, N extends StatementNamespace<K, ?, ?>> void addContext(final Class<@NonNull N> namespace,
final KT key,final StmtContext<?, ?, ?> stmt) {
*/
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();
}
return true;
}
- final StmtContext<Boolean, ?, ?> configStatement = StmtContextUtils.findFirstSubstatement(this,
- ConfigStatement.class);
final boolean isConfig;
- if (configStatement != null) {
- isConfig = configStatement.coerceStatementArgument();
+ final Optional<Boolean> 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(),
// Exists only to support {SubstatementContext,InferredStatementContext}.getSchemaPath()
@Deprecated
final @NonNull Optional<SchemaPath> substatementGetSchemaPath() {
- SchemaPath local = schemaPath;
- if (local == null) {
- synchronized (this) {
- local = schemaPath;
- if (local == null) {
- schemaPath = local = createSchemaPath(coerceParentContext());
- }
- }
+ if (schemaPath == null) {
+ schemaPath = createSchemaPath(coerceParentContext());
}
-
- return Optional.ofNullable(local);
+ return Optional.ofNullable(schemaPath);
}
@Deprecated