X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=yang%2Fyang-data-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fdata%2Fimpl%2Fschema%2Ftree%2FInMemoryDataTree.java;h=1078f74b17187f5b71e2ab6737091f1d2ffa84fc;hb=refs%2Fchanges%2F83%2F93883%2F2;hp=75c9af59b375b11d82a2bd0f5eb74158c9015f8a;hpb=a6ea70c09b13489918c387d54cde8f1095721acc;p=yangtools.git diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTree.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTree.java index 75c9af59b3..1078f74b17 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTree.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTree.java @@ -7,85 +7,115 @@ */ package org.opendaylight.yangtools.yang.data.impl.schema.tree; +import static java.util.Objects.requireNonNull; + import com.google.common.base.MoreObjects; -import com.google.common.base.Preconditions; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import javax.annotation.Nonnull; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.util.Optional; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeConfiguration; -import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree; import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode; import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode; import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree; -import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ContainerLike; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Read-only snapshot of the data tree. */ -final class InMemoryDataTree extends AbstractDataTreeTip implements TipProducingDataTree { - private static final AtomicReferenceFieldUpdater STATE_UPDATER = - AtomicReferenceFieldUpdater.newUpdater(InMemoryDataTree.class, DataTreeState.class, "state"); +final class InMemoryDataTree extends AbstractDataTreeTip implements DataTree { + private static final VarHandle STATE; + + static { + try { + STATE = MethodHandles.lookup().findVarHandle(InMemoryDataTree.class, "state", DataTreeState.class); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new ExceptionInInitializerError(e); + } + } + private static final Logger LOG = LoggerFactory.getLogger(InMemoryDataTree.class); private final DataTreeConfiguration treeConfig; private final boolean maskMandatory; /** - * Current data store state generation. + * Current data store state generation. All accesses need to go through {@link #STATE} */ + @SuppressWarnings("unused") private volatile DataTreeState state; InMemoryDataTree(final TreeNode rootNode, final DataTreeConfiguration treeConfig, - final SchemaContext schemaContext) { - this.treeConfig = Preconditions.checkNotNull(treeConfig, "treeConfig"); + final EffectiveModelContext schemaContext) { + this.treeConfig = requireNonNull(treeConfig, "treeConfig"); maskMandatory = true; state = DataTreeState.createInitial(rootNode); if (schemaContext != null) { - setSchemaContext(schemaContext); + setEffectiveModelContext(schemaContext); } } InMemoryDataTree(final TreeNode rootNode, final DataTreeConfiguration treeConfig, - final SchemaContext schemaContext, final DataSchemaNode rootSchemaNode, final boolean maskMandatory) { - this.treeConfig = Preconditions.checkNotNull(treeConfig, "treeConfig"); + final EffectiveModelContext schemaContext, final DataSchemaNode rootSchemaNode, + final boolean maskMandatory) { + this.treeConfig = requireNonNull(treeConfig, "treeConfig"); this.maskMandatory = maskMandatory; state = DataTreeState.createInitial(rootNode).withSchemaContext(schemaContext, getOperation(rootSchemaNode)); } private ModificationApplyOperation getOperation(final DataSchemaNode rootSchemaNode) { - if (maskMandatory && rootSchemaNode instanceof ContainerSchemaNode) { - return new ContainerModificationStrategy((ContainerSchemaNode) rootSchemaNode, treeConfig); + if (rootSchemaNode instanceof ContainerLike && maskMandatory) { + return new ContainerModificationStrategy((ContainerLike) rootSchemaNode, treeConfig); + } + if (rootSchemaNode instanceof ListSchemaNode) { + final PathArgument arg = treeConfig.getRootPath().getLastPathArgument(); + if (arg instanceof NodeIdentifierWithPredicates) { + return maskMandatory ? new MapEntryModificationStrategy((ListSchemaNode) rootSchemaNode, treeConfig) + : MapEntryModificationStrategy.of((ListSchemaNode) rootSchemaNode, treeConfig); + } + } + + try { + return SchemaAwareApplyOperation.from(rootSchemaNode, treeConfig); + } catch (ExcludedDataSchemaNodeException e) { + throw new IllegalArgumentException("Root node does not belong current data tree", e); } + } - return SchemaAwareApplyOperation.from(rootSchemaNode, treeConfig); + @Override + public void setEffectiveModelContext(final EffectiveModelContext newModelContext) { + internalSetSchemaContext(newModelContext); } /* * This method is synchronized to guard against user attempting to install * multiple contexts. Otherwise it runs in a lock-free manner. */ - @Override - public synchronized void setSchemaContext(final SchemaContext newSchemaContext) { - Preconditions.checkNotNull(newSchemaContext); + private synchronized void internalSetSchemaContext(final EffectiveModelContext newSchemaContext) { + requireNonNull(newSchemaContext); LOG.debug("Following schema contexts will be attempted {}", newSchemaContext); final DataSchemaContextTree contextTree = DataSchemaContextTree.from(newSchemaContext); - final DataSchemaContextNode rootContextNode = contextTree.getChild(getRootPath()); - if (rootContextNode == null) { + final Optional> rootContextNode = contextTree.findChild(getRootPath()); + if (!rootContextNode.isPresent()) { LOG.warn("Could not find root {} in new schema context, not upgrading", getRootPath()); return; } - final DataSchemaNode rootSchemaNode = rootContextNode.getDataSchemaNode(); + final DataSchemaNode rootSchemaNode = rootContextNode.get().getDataSchemaNode(); if (!(rootSchemaNode instanceof DataNodeContainer)) { LOG.warn("Root {} resolves to non-container type {}, not upgrading", getRootPath(), rootSchemaNode); return; @@ -95,14 +125,15 @@ final class InMemoryDataTree extends AbstractDataTreeTip implements TipProducing DataTreeState currentState; DataTreeState newState; do { - currentState = state; + currentState = currentState(); newState = currentState.withSchemaContext(newSchemaContext, rootNode); - } while (!STATE_UPDATER.compareAndSet(this, currentState, newState)); + // TODO: can we lower this to compareAndSwapRelease? + } while (!STATE.compareAndSet(this, currentState, newState)); } @Override public InMemoryDataTreeSnapshot takeSnapshot() { - return state.newSnapshot(); + return currentState().newSnapshot(); } @Override @@ -110,10 +141,11 @@ final class InMemoryDataTree extends AbstractDataTreeTip implements TipProducing if (candidate instanceof NoopDataTreeCandidate) { return; } - Preconditions.checkArgument(candidate instanceof InMemoryDataTreeCandidate, "Invalid candidate class %s", - candidate.getClass()); - final InMemoryDataTreeCandidate c = (InMemoryDataTreeCandidate)candidate; + if (!(candidate instanceof InMemoryDataTreeCandidate)) { + throw new IllegalArgumentException("Invalid candidate class " + candidate.getClass()); + } + final InMemoryDataTreeCandidate c = (InMemoryDataTreeCandidate)candidate; if (LOG.isTraceEnabled()) { LOG.trace("Data Tree is {}", NormalizedNodes.toStringTree(c.getTipRoot().getData())); } @@ -122,7 +154,7 @@ final class InMemoryDataTree extends AbstractDataTreeTip implements TipProducing DataTreeState currentState; DataTreeState newState; do { - currentState = state; + currentState = currentState(); final TreeNode currentRoot = currentState.getRoot(); LOG.debug("Updating datastore from {} to {}", currentRoot, newRoot); @@ -136,13 +168,18 @@ final class InMemoryDataTree extends AbstractDataTreeTip implements TipProducing newState = currentState.withRoot(newRoot); LOG.trace("Updated state from {} to {}", currentState, newState); - } while (!STATE_UPDATER.compareAndSet(this, currentState, newState)); + // TODO: can we lower this to compareAndSwapRelease? + } while (!STATE.compareAndSet(this, currentState, newState)); } private static String simpleToString(final Object obj) { return obj.getClass().getName() + "@" + Integer.toHexString(obj.hashCode()); } + private DataTreeState currentState() { + return (DataTreeState) STATE.getAcquire(this); + } + @Override public YangInstanceIdentifier getRootPath() { return treeConfig.getRootPath(); @@ -153,13 +190,12 @@ final class InMemoryDataTree extends AbstractDataTreeTip implements TipProducing return MoreObjects.toStringHelper(this) .add("object", super.toString()) .add("config", treeConfig) - .add("state", state) + .add("state", currentState()) .toString(); } @Override - @Nonnull protected TreeNode getTipRoot() { - return state.getRoot(); + return currentState().getRoot(); } }