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%2FReactorStmtCtx.java;h=adca75ce7dcfadcc61bd3abf95ea34660cd02901;hb=b328a8b8128b20de5aca908ae74ee5711cb0d2d1;hp=e4b0dd37a25d214a6f1f7a37e5906dfdb5c5272f;hpb=246158dab180ba6dc585c97cf2e786e842a2e688;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 e4b0dd37a2..adca75ce7d 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 @@ -42,6 +42,7 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Regist import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; 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.SourceException; import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace; import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace.SupportedFeatures; import org.slf4j.Logger; @@ -320,6 +321,20 @@ abstract class ReactorStmtCtx, E extends Effec abstract @NonNull E createEffective(); + /** + * Try to execute current {@link ModelProcessingPhase} of source parsing. If the phase has already been executed, + * this method does nothing. + * + * @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); + } + + abstract boolean doTryToCompletePhase(ModelProcessingPhase phase); + // // // Flags-based mechanics. These include public interfaces as well as all the crud we have lurking in our alignment @@ -397,8 +412,8 @@ abstract class ReactorStmtCtx, E extends Effec isConfig = optConfig.orElseThrow(); if (isConfig) { // Validity check: if parent is config=false this cannot be a config=true - InferenceException.throwIf(!parent.effectiveConfig(), sourceReference(), - "Parent node has config=false, this node must not be specifed as config=true"); + InferenceException.throwIf(!parent.effectiveConfig(), this, + "Parent node has config=false, this node must not be specifed as config=true"); } } else { // If "config" statement is not specified, the default is the same as the parent's "config" value. @@ -530,6 +545,16 @@ abstract class ReactorStmtCtx, E extends Effec // // + /** + * Local knowledge of {@link #refcount} values up to statement root. We use this field to prevent recursive lookups + * in {@link #noParentRefs(StatementContextBase)} -- once we discover a parent reference once, we keep that + * knowledge and update it when {@link #sweep()} is invoked. + */ + private byte parentRef = PARENTREF_UNKNOWN; + private static final byte PARENTREF_UNKNOWN = -1; + private static final byte PARENTREF_ABSENT = 0; + private static final byte PARENTREF_PRESENT = 1; + /** * Acquire a reference on this context. As long as there is at least one reference outstanding, * {@link #buildEffective()} will not result in {@link #effectiveSubstatements()} being discarded. @@ -567,28 +592,60 @@ abstract class ReactorStmtCtx, E extends Effec refcount = current - 1; LOG.trace("Refcount {} on {}", refcount, this); - if (isSweepable()) { + + if (refcount == REFCOUNT_NONE) { + lastDecRef(); + } + } + + private void lastDecRef() { + if (noImplictRef()) { // We are no longer guarded by effective instance sweepOnDecrement(); + return; + } + + final byte prevRefs = parentRef; + if (prevRefs == PARENTREF_ABSENT) { + // We are the last reference towards root, any children who observed PARENTREF_PRESENT from us need to be + // updated + markNoParentRef(); + } else if (prevRefs == PARENTREF_UNKNOWN) { + // Noone observed our parentRef, just update it + loadParentRefcount(); } } - /** - * Sweep this statement context as a result of {@link #sweepSubstatements()}, i.e. when parent is also being swept. - */ - private void sweep() { - if (isSweepable()) { - LOG.trace("Releasing {}", this); - sweepState(); + static final void markNoParentRef(final Collection> substatements) { + for (ReactorStmtCtx stmt : substatements) { + final byte prevRef = stmt.parentRef; + stmt.parentRef = PARENTREF_ABSENT; + if (prevRef == PARENTREF_PRESENT && stmt.refcount == REFCOUNT_NONE) { + // Child thinks it is pinned down, update its perspective + stmt.markNoParentRef(); + } } } + abstract void markNoParentRef(); + static final void sweep(final Collection> substatements) { for (ReactorStmtCtx stmt : substatements) { stmt.sweep(); } } + /** + * Sweep this statement context as a result of {@link #sweepSubstatements()}, i.e. when parent is also being swept. + */ + private void sweep() { + parentRef = PARENTREF_ABSENT; + if (refcount == REFCOUNT_NONE && noImplictRef()) { + LOG.trace("Releasing {}", this); + sweepState(); + } + } + static final int countUnswept(final Collection> substatements) { int result = 0; for (ReactorStmtCtx stmt : substatements) { @@ -614,7 +671,7 @@ abstract class ReactorStmtCtx, E extends Effec // Called when this statement does not have an implicit reference and have reached REFCOUNT_NONE private void sweepOnDecrement() { LOG.trace("Sweeping on decrement {}", this); - if (noParentRefcount()) { + if (noParentRef()) { // No further parent references, sweep our state. sweepState(); } @@ -642,7 +699,7 @@ abstract class ReactorStmtCtx, E extends Effec } // parent is potentially reclaimable - if (noParentRefcount()) { + if (noParentRef()) { LOG.trace("Cleanup {} of parent {}", refcount, this); if (sweepState()) { final ReactorStmtCtx parent = getParentContext(); @@ -657,29 +714,40 @@ abstract class ReactorStmtCtx, E extends Effec return effectiveInstance != null || !isSupportedToBuildEffective(); } - // FIXME: cache the resolution of this - private boolean noParentRefcount() { + private boolean noParentRef() { + return parentRefcount() == PARENTREF_ABSENT; + } + + private byte parentRefcount() { + final byte refs; + return (refs = parentRef) != PARENTREF_UNKNOWN ? refs : loadParentRefcount(); + } + + private byte loadParentRefcount() { + return parentRef = calculateParentRefcount(); + } + + private byte calculateParentRefcount() { final ReactorStmtCtx parent = getParentContext(); - if (parent != null) { - // There are three possibilities: - // - REFCOUNT_NONE, in which case we need to search next parent - // - negative (< REFCOUNT_NONE), meaning parent is in some stage of sweeping, hence it does not have - // a reference to us - // - positive (> REFCOUNT_NONE), meaning parent has an explicit refcount which is holding us down - final int refs = parent.refcount; - return refs == REFCOUNT_NONE ? parent.noParentRefcount() : refs < REFCOUNT_NONE; + if (parent == null) { + return PARENTREF_ABSENT; + } + // There are three possibilities: + // - REFCOUNT_NONE, in which case we need to search next parent + // - negative (< REFCOUNT_NONE), meaning parent is in some stage of sweeping, hence it does not have + // a reference to us + // - positive (> REFCOUNT_NONE), meaning parent has an explicit refcount which is holding us down + final int refs = parent.refcount; + if (refs == REFCOUNT_NONE) { + return parent.parentRefcount(); } - return true; + return refs < REFCOUNT_NONE ? PARENTREF_ABSENT : PARENTREF_PRESENT; } private boolean isAwaitingChildren() { return refcount > REFCOUNT_SWEEPING && refcount < REFCOUNT_NONE; } - private boolean isSweepable() { - return refcount == REFCOUNT_NONE && noImplictRef(); - } - private void sweepOnChildDone() { LOG.trace("Sweeping on child done {}", this); final int current = refcount;