From: Robert Varga Date: Thu, 22 May 2014 20:49:47 +0000 (+0200) Subject: BUG-509: create data tree SPI package X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~33^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=581592c46b0afa911f738b32b5ca33148c1e77bd BUG-509: create data tree SPI package This patch introduces an SPI package, which contains the metadata tree node abstraction and reference implementation. This will substitute the StoreMetadataNode class. Major improvement is the isolation of lifecycle from the rest of the implementation and major reduction in memory usage, as leaf nodes no longer need to lug a HashMap around. Change-Id: I89215672006b1ed6064feaf186c94c05550d299e Signed-off-by: Robert Varga --- diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/AbstractTreeNode.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/AbstractTreeNode.java new file mode 100644 index 0000000000..1cf28a36d1 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/AbstractTreeNode.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl.tree.spi; + +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +import com.google.common.base.Preconditions; +import com.google.common.primitives.UnsignedLong; + +/* + * A very basic data tree node. + */ +abstract class AbstractTreeNode implements TreeNode { + private final NormalizedNode data; + private final UnsignedLong version; + + protected AbstractTreeNode(final NormalizedNode data, final UnsignedLong version) { + this.data = Preconditions.checkNotNull(data); + this.version = Preconditions.checkNotNull(version); + } + + @Override + public PathArgument getIdentifier() { + return data.getIdentifier(); + } + + @Override + public final UnsignedLong getVersion() { + return version; + } + + @Override + public final NormalizedNode getData() { + return data; + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/ContainerNode.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/ContainerNode.java new file mode 100644 index 0000000000..20bf61914f --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/ContainerNode.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl.tree.spi; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer; +import org.opendaylight.yangtools.yang.data.api.schema.OrderedNodeContainer; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.primitives.UnsignedLong; + +/** + * A TreeNode capable of holding child nodes. The fact that any of the children + * changed is tracked by the subtree version. + */ +final class ContainerNode extends AbstractTreeNode { + private final Map children; + private final UnsignedLong subtreeVersion; + + protected ContainerNode(final NormalizedNode data, final UnsignedLong version, + final Map children, final UnsignedLong subtreeVersion) { + super(data, version); + this.children = Preconditions.checkNotNull(children); + this.subtreeVersion = Preconditions.checkNotNull(subtreeVersion); + } + + @Override + public UnsignedLong getSubtreeVersion() { + return subtreeVersion; + } + + @Override + public Optional getChild(final PathArgument key) { + return Optional.fromNullable(children.get(key)); + } + + @Override + public MutableTreeNode mutable() { + return new Mutable(this); + } + + private static final class Mutable implements MutableTreeNode { + private final Map children; + private final UnsignedLong version; + private NormalizedNode data; + private UnsignedLong subtreeVersion; + + private Mutable(final ContainerNode parent) { + this.data = parent.getData(); + this.children = new HashMap<>(parent.children); + this.subtreeVersion = parent.getSubtreeVersion(); + this.version = parent.getVersion(); + } + + @Override + public Optional getChild(final PathArgument child) { + return Optional.fromNullable(children.get(child)); + } + + @Override + public void setSubtreeVersion(final UnsignedLong subtreeVersion) { + this.subtreeVersion = Preconditions.checkNotNull(subtreeVersion); + } + + @Override + public void addChild(final TreeNode child) { + children.put(child.getIdentifier(), child); + } + + @Override + public void removeChild(final PathArgument id) { + children.remove(id); + } + + @Override + public TreeNode seal() { + final Map realChildren; + + if (children.isEmpty()) { + realChildren = Collections.emptyMap(); + } else { + realChildren = children; + } + + return new ContainerNode(data, version, realChildren, subtreeVersion); + } + + @Override + public void setData(final NormalizedNode data) { + this.data = Preconditions.checkNotNull(data); + } + } + + private static ContainerNode create(final UnsignedLong version, final NormalizedNode data, final Iterable> children) { + final Map map = new HashMap<>(); + + for (NormalizedNode child : children) { + map.put(child.getIdentifier(), TreeNodeFactory.createTreeNode(child, version)); + } + + return new ContainerNode(data, version, map, version); + } + + public static ContainerNode create(final UnsignedLong version, final NormalizedNodeContainer> container) { + return create(version, container, container.getValue()); + } + + public static ContainerNode create(final UnsignedLong version, final OrderedNodeContainer> container) { + return create(version, container, container.getValue()); + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/MutableTreeNode.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/MutableTreeNode.java new file mode 100644 index 0000000000..84300a9fd0 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/MutableTreeNode.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl.tree.spi; + +import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +import com.google.common.primitives.UnsignedLong; + +public interface MutableTreeNode extends StoreTreeNode { + void setData(NormalizedNode data); + void setSubtreeVersion(UnsignedLong subtreeVersion); + void addChild(TreeNode child); + void removeChild(PathArgument id); + TreeNode seal(); +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/TreeNode.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/TreeNode.java new file mode 100644 index 0000000000..e3c35917e2 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/TreeNode.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl.tree.spi; + +import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode; +import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +import com.google.common.primitives.UnsignedLong; + +/* + * A very basic data tree node. It has a version (when it was last modified), + * a subtree version (when any of its children were modified) and some read-only + * data. + */ +public interface TreeNode extends Identifiable, StoreTreeNode { + /** + * Get the data node version. + * + * @return Current data node version. + */ + UnsignedLong getVersion(); + + /** + * Get the subtree version. + * + * @return Current subtree version. + */ + UnsignedLong getSubtreeVersion(); + + /** + * Get a read-only view of the underlying data. + * + * @return Unmodifiable view of the underlying data. + */ + NormalizedNode getData(); + + /** + * Get a mutable, isolated copy of the node. + * + * @return Mutable copy + */ + MutableTreeNode mutable(); +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/TreeNodeFactory.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/TreeNodeFactory.java new file mode 100644 index 0000000000..03c3ab8447 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/TreeNodeFactory.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl.tree.spi; + +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer; +import org.opendaylight.yangtools.yang.data.api.schema.OrderedNodeContainer; + +import com.google.common.primitives.UnsignedLong; + +public final class TreeNodeFactory { + private TreeNodeFactory() { + throw new UnsupportedOperationException("Utility class should not be instantiated"); + } + + /** + * Create a new AbstractTreeNode from a data node, descending recursively as needed. + * This method should only ever be used for new data. + * + * @param data data node + * @param version data node version + * @return new AbstractTreeNode instance, covering the data tree provided + */ + public static final TreeNode createTreeNode(final NormalizedNode data, final UnsignedLong version) { + if (data instanceof NormalizedNodeContainer) { + @SuppressWarnings("unchecked") + NormalizedNodeContainer> container = (NormalizedNodeContainer>) data; + return ContainerNode.create(version, container); + + } + if (data instanceof OrderedNodeContainer) { + @SuppressWarnings("unchecked") + OrderedNodeContainer> container = (OrderedNodeContainer>) data; + return ContainerNode.create(version, container); + } + + return new ValueNode(data, version); + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/ValueNode.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/ValueNode.java new file mode 100644 index 0000000000..cbd2a17081 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/spi/ValueNode.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl.tree.spi; + +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.primitives.UnsignedLong; + +final class ValueNode extends AbstractTreeNode { + private static final Logger LOG = LoggerFactory.getLogger(ValueNode.class); + + protected ValueNode(final NormalizedNode data, final UnsignedLong version) { + super(data, version); + } + + @Override + public Optional getChild(final PathArgument childId) { + LOG.warn("Attempted to access child {} of value-node {}", childId, this); + return Optional.absent(); + } + + @Override + public UnsignedLong getSubtreeVersion() { + return getVersion(); + } + + @Override + public MutableTreeNode mutable() { + /** + * Value nodes can only we read/written/delete, which does a straight + * replace. That means they don't haver need to be made mutable. + */ + throw new UnsupportedOperationException(String.format("Attempted to mutate value-node %s", this)); + } +}