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=13070428ec896c1722f01454bdd2841a4b25fcab;hb=5500c3ce51088ed6de1adedd35f52662a8304b1e;hp=c5303e1dbed558c54d2ca709959a98bdff0710c8;hpb=c09f1b86f83b288bd412c480c2c7b27ee2174258;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 c5303e1dbe..13070428ec 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,130 +7,135 @@ */ package org.opendaylight.yangtools.yang.data.impl.schema.tree; -import com.google.common.base.Optional; +import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; -import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType; +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.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.DataNodeContainer; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - /** * Read-only snapshot of the data tree. */ -final class InMemoryDataTree implements DataTree { +final class InMemoryDataTree extends AbstractDataTreeTip implements TipProducingDataTree { + private static final AtomicReferenceFieldUpdater STATE_UPDATER = + AtomicReferenceFieldUpdater.newUpdater(InMemoryDataTree.class, DataTreeState.class, "state"); private static final Logger LOG = LoggerFactory.getLogger(InMemoryDataTree.class); - private static final InstanceIdentifier PUBLIC_ROOT_PATH = InstanceIdentifier.builder().build(); - private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true); - private ModificationApplyOperation applyOper = new AlwaysFailOperation(); - private SchemaContext currentSchemaContext; - private TreeNode rootNode; + private final YangInstanceIdentifier rootPath; + private final TreeType treeType; - public InMemoryDataTree(final TreeNode rootNode, final SchemaContext schemaContext) { - this.rootNode = Preconditions.checkNotNull(rootNode); + /** + * Current data store state generation. + */ + 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"); + state = DataTreeState.createInitial(rootNode); if (schemaContext != null) { - // Also sets applyOper setSchemaContext(schemaContext); } } + /* + * 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); - LOG.info("Attepting to install schema context {}", newSchemaContext); - - /* - * FIXME: we should walk the schema contexts, both current and new and see - * whether they are compatible here. Reject incompatible changes. - */ + LOG.debug("Following schema contexts will be attempted {}", newSchemaContext); - // Instantiate new apply operation, this still may fail - final ModificationApplyOperation newApplyOper = SchemaAwareApplyOperation.from(newSchemaContext); - - // Ready to change the context now, make sure no operations are running - rwLock.writeLock().lock(); - try { - this.applyOper = newApplyOper; - this.currentSchemaContext = newSchemaContext; - } finally { - rwLock.writeLock().unlock(); + 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); + return; } - } - @Override - public InMemoryDataTreeSnapshot takeSnapshot() { - rwLock.readLock().lock(); - try { - return new InMemoryDataTreeSnapshot(currentSchemaContext, rootNode, applyOper); - } finally { - rwLock.readLock().unlock(); + final DataSchemaNode rootSchemaNode = rootContextNode.getDataSchemaNode(); + if (!(rootSchemaNode instanceof DataNodeContainer)) { + LOG.warn("Root {} resolves to non-container type {}, not upgrading", rootPath, rootSchemaNode); + return; } - } - @Override - public void validate(final DataTreeModification modification) throws DataValidationFailedException { - Preconditions.checkArgument(modification instanceof InMemoryDataTreeModification, "Invalid modification class %s", modification.getClass()); + 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); + } - final InMemoryDataTreeModification m = (InMemoryDataTreeModification)modification; - m.getStrategy().checkApplicable(PUBLIC_ROOT_PATH, m.getRootModification(), Optional.of(rootNode)); + DataTreeState currentState, newState; + do { + currentState = state; + newState = currentState.withSchemaContext(newSchemaContext, rootNode); + } while (!STATE_UPDATER.compareAndSet(this, currentState, newState)); } @Override - public synchronized DataTreeCandidate prepare(final DataTreeModification modification) { - Preconditions.checkArgument(modification instanceof InMemoryDataTreeModification, "Invalid modification class %s", modification.getClass()); - - final InMemoryDataTreeModification m = (InMemoryDataTreeModification)modification; - final ModifiedNode root = m.getRootModification(); - - if (root.getType() == ModificationType.UNMODIFIED) { - return new NoopDataTreeCandidate(PUBLIC_ROOT_PATH, root); - } - - rwLock.writeLock().lock(); - try { - final Optional newRoot = m.getStrategy().apply(m.getRootModification(), - Optional.of(rootNode), rootNode.getSubtreeVersion().next()); - Preconditions.checkState(newRoot.isPresent(), "Apply strategy failed to produce root node"); - return new InMemoryDataTreeCandidate(PUBLIC_ROOT_PATH, root, rootNode, newRoot.get()); - } finally { - rwLock.writeLock().unlock(); - } + public InMemoryDataTreeSnapshot takeSnapshot() { + return state.newSnapshot(); } @Override - public synchronized void commit(final DataTreeCandidate candidate) { + public void commit(final DataTreeCandidate candidate) { if (candidate instanceof NoopDataTreeCandidate) { return; } - Preconditions.checkArgument(candidate instanceof InMemoryDataTreeCandidate, "Invalid candidate class %s", candidate.getClass()); final InMemoryDataTreeCandidate c = (InMemoryDataTreeCandidate)candidate; - LOG.debug("Updating datastore from {} to {}", rootNode, c.getAfterRoot()); - if (LOG.isTraceEnabled()) { - LOG.trace("Data Tree is {}", StoreUtils.toStringTree(c.getAfterRoot().getData())); + LOG.trace("Data Tree is {}", NormalizedNodes.toStringTree(c.getTipRoot().getData())); } - // Ready to change the context now, make sure no operations are running - rwLock.writeLock().lock(); - try { - Preconditions.checkState(c.getBeforeRoot() == rootNode, - String.format("Store tree %s and candidate base %s differ.", rootNode, c.getBeforeRoot())); - this.rootNode = c.getAfterRoot(); - } finally { - rwLock.writeLock().unlock(); - } + final TreeNode newRoot = c.getTipRoot(); + DataTreeState currentState, newState; + do { + currentState = state; + 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); + + newState = currentState.withRoot(newRoot); + LOG.trace("Updated state from {} to {}", currentState, newState); + } while (!STATE_UPDATER.compareAndSet(this, currentState, newState)); + } + + @Override + public YangInstanceIdentifier getRootPath() { + return rootPath; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this). + add("object", super.toString()). + add("rootPath", rootPath). + add("state", state). + toString(); + } + + @Override + protected TreeNode getTipRoot() { + return state.getRoot(); } }