X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=yang%2Fyang-parser-reactor%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Fstmt%2Freactor%2FReactorStmtCtx.java;h=f292bab919fbef8adf8685190b89a4aca9161226;hb=8488b897c91e03c4e00ca61064fadd2f97834dc0;hp=a7f3941042514ddce09e8ca85b954ae8c8f3d9e4;hpb=b1c563b20a316b45640668b748c02963bab95814;p=yangtools.git diff --git a/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ReactorStmtCtx.java b/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ReactorStmtCtx.java index a7f3941042..f292bab919 100644 --- a/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ReactorStmtCtx.java +++ b/yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ReactorStmtCtx.java @@ -38,6 +38,7 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current; import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase; +import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.ExecutionOrder; import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry; import org.opendaylight.yangtools.yang.parser.spi.meta.ParserNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; @@ -112,6 +113,11 @@ abstract class ReactorStmtCtx, E extends Effec */ private static final int REFCOUNT_SWEPT = Integer.MIN_VALUE; + /** + * Effective instance built from this context. This field as dual types. Under normal circumstances in matches the + * {@link #buildEffective()} instance. If this context is reused, it can be inflated to {@link EffectiveInstances} + * and also act as a common instance reuse site. + */ private @Nullable E effectiveInstance; // Master flag controlling whether this context can yield an effective statement @@ -148,14 +154,16 @@ abstract class ReactorStmtCtx, E extends Effec // hence improve memory layout. private byte flags; - // Flag for use with AbstractResumedStatement. This is hiding in the alignment shadow created by above boolean + // Flag for use by AbstractResumedStatement, ReplicaStatementContext and InferredStatementContext. Each of them + // uses it to indicated a different condition. This is hiding in the alignment shadow created by + // 'isSupportedToBuildEffective'. // FIXME: move this out once we have JDK15+ - private boolean fullyDefined; + private boolean boolFlag; // 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. - @Deprecated - private volatile SchemaPath schemaPath; + // FIXME: this should become 'QName' + private SchemaPath schemaPath; ReactorStmtCtx() { // Empty on purpose @@ -163,7 +171,13 @@ abstract class ReactorStmtCtx, E extends Effec ReactorStmtCtx(final ReactorStmtCtx original) { isSupportedToBuildEffective = original.isSupportedToBuildEffective; - fullyDefined = original.fullyDefined; + boolFlag = original.boolFlag; + flags = original.flags; + } + + // Used by ReplicaStatementContext only + ReactorStmtCtx(final ReactorStmtCtx original, final Void dummy) { + boolFlag = isSupportedToBuildEffective = original.isSupportedToBuildEffective; flags = original.flags; } @@ -239,9 +253,29 @@ abstract class ReactorStmtCtx, E extends Effec return getOriginalCtx().map(StmtContext::buildEffective).orElse(null); } + // + // In the next two methods we are looking for an effective statement. If we already have an effective instance, + // defer to it's implementation of the equivalent search. Otherwise we search our substatement contexts. + // + // Note that the search function is split, so as to allow InferredStatementContext to do its own thing first. + // + + @Override + public final > @NonNull Optional findSubstatementArgument( + final @NonNull Class type) { + final E existing = effectiveInstance; + return existing != null ? existing.findFirstEffectiveSubstatementArgument(type) + : findSubstatementArgumentImpl(type); + } + @Override - // Non-final due to InferredStatementContext's override - public > @NonNull Optional findSubstatementArgument( + public final boolean hasSubstatement(final @NonNull Class> type) { + final E existing = effectiveInstance; + return existing != null ? existing.findFirstEffectiveSubstatement(type).isPresent() : hasSubstatementImpl(type); + } + + // Visible due to InferredStatementContext's override. At this point we do not have an effective instance available. + > @NonNull Optional findSubstatementArgumentImpl( final @NonNull Class type) { return allSubstatementsStream() .filter(ctx -> ctx.isSupportedToBuildEffective() && ctx.producesEffective(type)) @@ -249,9 +283,8 @@ abstract class ReactorStmtCtx, E extends Effec .map(ctx -> (X) ctx.getArgument()); } - @Override - // Non-final due to InferredStatementContext's override - public boolean hasSubstatement(final @NonNull Class> type) { + // Visible due to InferredStatementContext's override. At this point we do not have an effective instance available. + boolean hasSubstatementImpl(final @NonNull Class> type) { return allSubstatementsStream() .anyMatch(ctx -> ctx.isSupportedToBuildEffective() && ctx.producesEffective(type)); } @@ -302,11 +335,6 @@ abstract class ReactorStmtCtx, E extends Effec return getLocalNamespace(type); } - @Override - protected final void checkLocalNamespaceAllowed(final Class> type) { - definition().checkNamespaceAllowed(type); - } - @Override protected > void onNamespaceElementAdded(final Class type, final K key, final V value) { @@ -349,14 +377,15 @@ abstract class ReactorStmtCtx, E extends Effec return (existing = effectiveInstance) != null ? existing : loadEffective(); } - private E loadEffective() { + private @NonNull E loadEffective() { // Creating an effective statement does not strictly require a declared instance -- there are statements like // 'input', which are implicitly defined. // Our implementation design makes an invariant assumption that buildDeclared() has been called by the time // we attempt to create effective statement: declared(); - final E ret = effectiveInstance = createEffective(); + final E ret = createEffective(); + effectiveInstance = ret; // we have called createEffective(), substatements are no longer guarded by us. Let's see if we can clear up // some residue. if (refcount == REFCOUNT_NONE) { @@ -367,19 +396,35 @@ abstract class ReactorStmtCtx, E extends Effec abstract @NonNull E createEffective(); + /** + * Walk this statement's copy history and return the statement closest to original which has not had its effective + * statements modified. This statement and returned substatement logically have the same set of substatements, hence + * share substatement-derived state. + * + * @return Closest {@link ReactorStmtCtx} with equivalent effective substatements + */ + abstract @NonNull ReactorStmtCtx unmodifiedEffectiveSource(); + + @Override + public final ModelProcessingPhase getCompletedPhase() { + return ModelProcessingPhase.ofExecutionOrder(executionOrder()); + } + + abstract byte executionOrder(); + /** * Try to execute current {@link ModelProcessingPhase} of source parsing. If the phase has already been executed, - * this method does nothing. + * this method does nothing. This must not be called with {@link ExecutionOrder#NULL}. * * @param phase to be executed (completed) * @return true if phase was successfully completed * @throws SourceException when an error occurred in source parsing */ - final boolean tryToCompletePhase(final ModelProcessingPhase phase) { - return phase.isCompletedBy(getCompletedPhase()) || doTryToCompletePhase(phase); + final boolean tryToCompletePhase(final byte executionOrder) { + return executionOrder() >= executionOrder || doTryToCompletePhase(executionOrder); } - abstract boolean doTryToCompletePhase(ModelProcessingPhase phase); + abstract boolean doTryToCompletePhase(byte targetOrder); // // @@ -509,14 +554,34 @@ abstract class ReactorStmtCtx, E extends Effec return false; } - // These two exist only due to memory optimization, should live in AbstractResumedStatement. We are also reusing - // this for ReplicaStatementContext's refcount tracking. + // These two exist only due to memory optimization, should live in AbstractResumedStatement. final boolean fullyDefined() { - return fullyDefined; + return boolFlag; } final void setFullyDefined() { - fullyDefined = true; + boolFlag = true; + } + + // This exists only due to memory optimization, should live in ReplicaStatementContext. In this context the flag + // indicates the need to drop source's reference count when we are being swept. + final boolean haveSourceReference() { + return boolFlag; + } + + // These three exist due to memory optimization, should live in InferredStatementContext. In this context the flag + // indicates whether or not this statement's substatement file was modified, i.e. it is not quite the same as the + // prototype's file. + final boolean isModified() { + return boolFlag; + } + + final void setModified() { + boolFlag = true; + } + + final void setUnmodified() { + boolFlag = false; } // These two exist only for StatementContextBase. Since we are squeezed for size, with only a single bit available @@ -539,9 +604,7 @@ abstract class ReactorStmtCtx, E extends Effec @Override public final QName argumentAsTypeQName() { - final Object argument = argument(); - verify(argument instanceof String, "Unexpected argument %s", argument); - return interpretAsQName((String) argument); + return interpretAsQName(getRawArgument()); } @Override @@ -559,19 +622,13 @@ abstract class ReactorStmtCtx, E extends Effec // Exists only to support {SubstatementContext,InferredStatementContext}.schemaPath() @Deprecated final @Nullable SchemaPath substatementGetSchemaPath() { - SchemaPath local = schemaPath; - if (local == null) { - synchronized (this) { - local = schemaPath; - if (local == null) { - schemaPath = local = createSchemaPath((StatementContextBase) coerceParentContext()); - } - } + if (schemaPath == null) { + schemaPath = createSchemaPath((StatementContextBase) coerceParentContext()); } - - return local; + return schemaPath; } + // FIXME: 7.0.0: this method's logic needs to be moved to the respective StatementSupport classes @Deprecated private SchemaPath createSchemaPath(final StatementContextBase parent) { final SchemaPath parentPath = parent.getSchemaPath(); @@ -653,6 +710,7 @@ abstract class ReactorStmtCtx, E extends Effec } if (current <= REFCOUNT_NONE) { // Underflow, become defunct + // FIXME: add a global 'warn once' flag LOG.warn("Statement refcount underflow, reference counting disabled for {}", this, new Throwable()); refcount = REFCOUNT_DEFUNCT; return; @@ -667,12 +725,13 @@ abstract class ReactorStmtCtx, E extends Effec } /** - * Return {@code true} if this context has an outstanding reference. + * Return {@code true} if this context has no outstanding references. * - * @return True if this context has an outstanding reference. + * @return True if this context has no outstanding references. */ - final boolean haveRef() { - return refcount > REFCOUNT_NONE; + final boolean noRefs() { + final int local = refcount; + return local < REFCOUNT_NONE || local == REFCOUNT_NONE && noParentRef(); } private void lastDecRef() { @@ -861,6 +920,7 @@ abstract class ReactorStmtCtx, E extends Effec return true; } if (childRefs < 0 || childRefs >= REFCOUNT_DEFUNCT) { + // FIXME: add a global 'warn once' flag LOG.warn("Negative child refcount {} cannot be stored, reference counting disabled for {}", childRefs, this, new Throwable()); refcount = REFCOUNT_DEFUNCT;