X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-data-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fdata%2Fimpl%2Fschema%2Ftree%2FInMemoryDataTree.java;h=1078f74b17187f5b71e2ab6737091f1d2ffa84fc;hb=37380a5c65e213bc5f34b521d8f8e7d315df7465;hp=95165371c32c4491838da01c2d25cf51ce54277d;hpb=19c31f13e5040750d30cf9f4211913b2be04b403;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 95165371c3..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,91 +7,133 @@ */ 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.TipProducingDataTree; -import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeConfiguration; 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 YangInstanceIdentifier rootPath; - private final TreeType treeType; + 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; - public InMemoryDataTree(final TreeNode rootNode, final TreeType treeType, final YangInstanceIdentifier rootPath, final SchemaContext schemaContext) { - this.treeType = Preconditions.checkNotNull(treeType, "treeType"); - this.rootPath = Preconditions.checkNotNull(rootPath, "rootPath"); + InMemoryDataTree(final TreeNode rootNode, final DataTreeConfiguration 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 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 (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); } } + @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(rootPath); - if (rootContextNode == null) { - LOG.debug("Could not find root {} in new schema context, not upgrading", rootPath); + 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", rootPath, rootSchemaNode); + LOG.warn("Root {} resolves to non-container type {}, not upgrading", getRootPath(), rootSchemaNode); return; } - final ModificationApplyOperation rootNode; - if (rootSchemaNode instanceof ContainerSchemaNode) { - // FIXME: real root needs to enfore presence, but that require pre-population - rootNode = new ContainerModificationStrategy((ContainerSchemaNode) rootSchemaNode, treeType); - } else { - rootNode = SchemaAwareApplyOperation.from(rootSchemaNode, treeType); - } - - DataTreeState currentState, newState; + final ModificationApplyOperation rootNode = getOperation(rootSchemaNode); + 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 @@ -99,45 +141,61 @@ 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())); } final TreeNode newRoot = c.getTipRoot(); - DataTreeState currentState, newState; + DataTreeState currentState; + DataTreeState newState; do { - currentState = state; + currentState = currentState(); final TreeNode currentRoot = currentState.getRoot(); LOG.debug("Updating datastore from {} to {}", currentRoot, newRoot); final TreeNode oldRoot = c.getBeforeRoot(); - Preconditions.checkState(oldRoot == currentRoot, "Store tree %s and candidate base %s differ.", currentRoot, oldRoot); + if (oldRoot != currentRoot) { + final String oldStr = simpleToString(oldRoot); + final String currentStr = simpleToString(currentRoot); + throw new IllegalStateException("Store tree " + currentStr + " and candidate base " + oldStr + + " differ."); + } 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 rootPath; + return treeConfig.getRootPath(); } @Override public String toString() { - return MoreObjects.toStringHelper(this). - add("object", super.toString()). - add("rootPath", rootPath). - add("state", state). - toString(); + return MoreObjects.toStringHelper(this) + .add("object", super.toString()) + .add("config", treeConfig) + .add("state", currentState()) + .toString(); } @Override - @Nonnull protected TreeNode getTipRoot() { - return state.getRoot(); + return currentState().getRoot(); } }