Add NormalizedNodeContainer.size() 66/89266/1
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 22 Apr 2020 11:32:23 +0000 (13:32 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 22 Apr 2020 13:05:46 +0000 (15:05 +0200)
While the size of children is available through getValue(), it
is not completely efficient, as it may be forcing instantiation of
a Map.values() view.

Add NormalizedNodeContainer.size() to provide a more efficient way
of accessing this property. This has immediate benefits on both
MinMaxElementsValidation as well as general InMemoryDataTree
transaction performance.

JIRA: YANGTOOLS-1101
Change-Id: I607c2872645850400e4f242152059958729666b2
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
(cherry picked from commit 9fc5fe4197ae53e7e07ca79421fb3dec72c6d0d9)

13 files changed:
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/NormalizedNodeContainer.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/AbstractMutableContainerNode.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/LazyContainerNode.java
yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Bug890Test.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/ImmutableLeafSetNodeBuilder.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/ImmutableMapNodeBuilder.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/ImmutableOrderedMapNodeBuilder.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/nodes/AbstractImmutableDataContainerNode.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/MinMaxElementsValidation.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/BuilderTest.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/Bug2690Test.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/Bug4454Test.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/ListConstraintsValidation.java

index df81ece42032fa7d966ea83def39605822f11a41..536b15883060562f80c01e49d367c501cc2f36b8 100644 (file)
@@ -12,23 +12,19 @@ import java.util.Optional;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 
 /**
- * Node which is not leaf, but has child {@link NormalizedNode}s as its valzue.
+ * Node which is not leaf, but has child {@link NormalizedNode}s as its value.
  *
  * <p>
- * NormalizedNodeContainer does not have a value, but it has a child
- * nodes. Definition of possible and valid child nodes is introduced
- * in subclasses of this interface.
+ * NormalizedNodeContainer does not have a value, but it has a child nodes. Definition of possible and valid child nodes
+ * is introduced in subclasses of this interface.
  *
  * <p>
- * This interface should not be used directly, but rather use of of derived subinterfaces
- * such as {@link DataContainerNode}, {@link MapNode}, {@link LeafSetNode}.
+ * This interface should not be used directly, but rather use of of derived subclasses such as
+ * {@link DataContainerNode}, {@link MapNode}, {@link LeafSetNode}.
  *
- * @param <I>
- *            Node Identifier type
- * @param <K>
- *            Child Node Identifier type
- * @param <V>
- *            Child Node type
+ * @param <I> Node Identifier type
+ * @param <K> Child Node Identifier type
+ * @param <V> Child Node type
  */
 public interface NormalizedNodeContainer<I extends PathArgument, K extends PathArgument,
        V extends NormalizedNode<? extends K, ?>> extends NormalizedNode<I, Collection<V>> {
@@ -38,18 +34,29 @@ public interface NormalizedNodeContainer<I extends PathArgument, K extends PathA
 
     /**
      * Returns immutable iteration of child nodes of this node.
-     *
      */
     @Override
     Collection<V> getValue();
 
+    /**
+     * Return the logical size of this container, i.e. the number of children in contains.
+     *
+     * <p>
+     * Default implementation defers to the collection returned by {@link #getValue()}. Implementations are strongly
+     * encouraged to provide a more efficient implementation of this method.
+     *
+     * @return Number of child nodes in this container.
+     */
+    // FIXME: 6.0.0: consider making this method non-default
+    default int size() {
+        return getValue().size();
+    }
+
     /**
      * Returns child node identified by provided key.
      *
-     * @param child
-     *            Path argument identifying child node
-     * @return Optional with child node if child exists.
-     *         {@link Optional#empty()} if child does not exists.
+     * @param child Path argument identifying child node
+     * @return Optional with child node if child exists. {@link Optional#empty()} if child does not exist.
      */
     Optional<V> getChild(K child);
 }
index 3106e369c8bbe04ce16e2b985551293c7011bb31..22b2488c9f14ab840fdcab99ae2491ddb213fb22 100644 (file)
@@ -81,10 +81,11 @@ abstract class AbstractMutableContainerNode implements MutableTreeNode {
          */
         if (!version.equals(subtreeVersion)) {
             final Map<PathArgument, TreeNode> newChildren = MapAdaptor.getDefaultInstance().optimize(children);
-            final int dataSize = getData().getValue().size();
-            if (dataSize != newChildren.size()) {
-                verify(dataSize > newChildren.size(), "Detected %s modified children, data has only %s",
-                    newChildren.size(), dataSize);
+            final int dataSize = getData().size();
+            final int childrenSize = newChildren.size();
+            if (dataSize != childrenSize) {
+                verify(dataSize > childrenSize, "Detected %s modified children, data has only %s",
+                    childrenSize, dataSize);
                 ret = new LazyContainerNode(data, version, newChildren, subtreeVersion);
             } else {
                 ret = new MaterializedContainerNode(data, version, newChildren, subtreeVersion);
index c576df55ac03b43d239a36f33a2806ac3e98d552..666b8d3372a9e6793ff2f59ceefec60e808658f9 100644 (file)
@@ -32,7 +32,7 @@ final class LazyContainerNode extends AbstractModifiedContainerNode {
     @Override
     public MutableTreeNode mutable() {
         final Map<PathArgument, TreeNode> snapshot = snapshotChildren();
-        if (snapshot.size() == castData().getValue().size()) {
+        if (snapshot.size() == castData().size()) {
             return new MaterializedMutableContainerNode(this, snapshot);
         }
 
index 6afd5d6933c8394833e5ab2c065a4c03eda56db8..d97c185f7cbf2720e8365727d84d1fbb2b1bb27b 100644 (file)
@@ -84,7 +84,7 @@ public class Bug890Test {
         assertTrue(outgoingLabelsList.orElse(null) instanceof MapNode);
         MapNode outgoingLabelsMap = (MapNode) outgoingLabelsList.get();
 
-        assertEquals(2, outgoingLabelsMap.getValue().size());
+        assertEquals(2, outgoingLabelsMap.size());
         Collection<MapEntryNode> labels = outgoingLabelsMap.getValue();
         NodeIdentifierWithPredicates firstNodeId =
                 NodeIdentifierWithPredicates.of(OUTGOING_LABELS_QNAME, INDEX_QNAME, 0);
index 46d8361897ff2b538e63b6111fb4ba0b4a91dff1..0edc0b9f2573c65b6b9db07dacc2f97a737596d4 100644 (file)
@@ -119,6 +119,11 @@ public class ImmutableLeafSetNodeBuilder<T> implements ListNodeBuilder<T, LeafSe
             return Optional.ofNullable(children.get(child));
         }
 
+        @Override
+        public int size() {
+            return children.size();
+        }
+
         @Override
         protected int valueHashCode() {
             return children.hashCode();
index 02546802cfba053a4f8e0ab6de40034bae20049a..8152a2e3b01615a63ac28cc7a81bc3c5d8505208 100644 (file)
@@ -102,7 +102,6 @@ public class ImmutableMapNodeBuilder implements CollectionNodeBuilder<MapEntryNo
         return withChild(child);
     }
 
-
     @Override
     public NormalizedNodeContainerBuilder<NodeIdentifier, PathArgument, MapEntryNode, MapNode> removeChild(
             final PathArgument key) {
@@ -130,6 +129,11 @@ public class ImmutableMapNodeBuilder implements CollectionNodeBuilder<MapEntryNo
             return UnmodifiableCollection.create(children.values());
         }
 
+        @Override
+        public int size() {
+            return children.size();
+        }
+
         @Override
         protected int valueHashCode() {
             return children.hashCode();
index dcf17eab387862fb869424da5144ea8f6b1af9b8..178525be51563cfb83c077202cee229fc8623342 100644 (file)
@@ -146,6 +146,11 @@ public class ImmutableOrderedMapNodeBuilder implements CollectionNodeBuilder<Map
             return Iterables.get(children.values(), position);
         }
 
+        @Override
+        public int size() {
+            return children.size();
+        }
+
         @Override
         protected int valueHashCode() {
             return children.hashCode();
index 231a703e3c5912a2036980500090836d7beb924c..2543f435d217f432a64a2b445badfbd9090a2622 100644 (file)
@@ -37,6 +37,11 @@ public abstract class AbstractImmutableDataContainerNode<K extends PathArgument>
         return children.values();
     }
 
+    @Override
+    public final int size() {
+        return children.size();
+    }
+
     @Override
     protected int valueHashCode() {
         return children.hashCode();
index 6c2ad21a7183477bfce140dc107fa2fb0c668811..d1a390b7c240cd76bd1611d9bfc96f87aecb01cb 100644 (file)
@@ -150,7 +150,7 @@ final class MinMaxElementsValidation<T extends DataSchemaNode & ElementCountCons
 
     private static int numOfChildrenFromValue(final NormalizedNode<?, ?> value) {
         if (value instanceof NormalizedNodeContainer) {
-            return ((NormalizedNodeContainer<?, ?, ?>) value).getValue().size();
+            return ((NormalizedNodeContainer<?, ?, ?>) value).size();
         } else if (value instanceof UnkeyedListNode) {
             return ((UnkeyedListNode) value).getSize();
         }
index 98e683aa50fd4a49508778b14733a12c8ee539d8..f24a45c3f36a86f0bfa60a15469049daf5c9537c 100644 (file)
@@ -131,7 +131,7 @@ public class BuilderTest {
         assertEquals(orderedMapNodeCreateNode.getSize(), orderedMapNodeCreateNull.getSize() - 1);
         assertEquals(NODE_IDENTIFIER_LIST, orderedMapNodeCreateSize.getIdentifier());
         assertEquals(LIST_MAIN_CHILD_1, orderedMapNodeCreateNull.getChild(0));
-        assertEquals(SIZE, orderedMapNodeCreateNull.getValue().size());
+        assertEquals(SIZE, orderedMapNodeCreateNull.size());
         assertEquals(orderedMapNodeSchemaAware.getChild(0), orderedMapNodeSchemaAwareMapNodeConst.getChild(0));
     }
 
index d22a68fca5690de81db6c5372dfa273715520c8a..579fa2ea182d6b93d6df625e5ef28b5ac72fb6aa 100644 (file)
@@ -65,7 +65,7 @@ public class Bug2690Test extends AbstractTestModelTest {
         final DataTreeModification modificationAfterTx = snapshotAfterTx.newModification();
         final Optional<NormalizedNode<?, ?>> readNode = modificationAfterTx.readNode(TestModel.OUTER_LIST_PATH);
         assertTrue(readNode.isPresent());
-        assertEquals(2, ((NormalizedNodeContainer<?,?,?>)readNode.get()).getValue().size());
+        assertEquals(2, ((NormalizedNodeContainer<?,?,?>)readNode.get()).size());
     }
 
     @Test
index e33347e08cfa42515ce0c8721e2ddd88a679ae6a..9d05210203107461574c4360acc855f2161d729c 100644 (file)
@@ -230,7 +230,7 @@ public class Bug4454Test {
         DataTreeSnapshot test2 = inMemoryDataTree.takeSnapshot();
         minMaxListRead = test2.readNode(MIN_MAX_LIST_PATH);
         assertTrue(minMaxListRead.isPresent());
-        assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 3);
+        assertEquals(3, ((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).size());
 
         DataTreeModification tempMod2 = test2.newModification();
         tempMod2.write(MIN_MAX_LIST_PATH, mapNodeBaz);
@@ -244,7 +244,7 @@ public class Bug4454Test {
         DataTreeSnapshot test3 = inMemoryDataTree.takeSnapshot();
         minMaxListRead = test3.readNode(MIN_MAX_LIST_PATH);
         assertTrue(minMaxListRead.isPresent());
-        assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 1);
+        assertEquals(1, ((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).size());
         assertTrue(minMaxListRead.get().getValue().toString().contains("test2"));
 
         DataTreeModification tempMod3 = test3.newModification();
@@ -303,7 +303,7 @@ public class Bug4454Test {
         final Optional<NormalizedNodeContainer<?, ?, ?>> leafList = ((NormalizedNodeContainer) masterContainer.get())
                 .getChild(new NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME));
         assertTrue(leafList.isPresent());
-        assertTrue(leafList.get().getValue().size() == 3);
+        assertEquals(3, leafList.get().size());
     }
 
     @Test
@@ -346,7 +346,7 @@ public class Bug4454Test {
         final NormalizedNode<?, ?> data = inMemoryDataTree.takeSnapshot()
                 .readNode(YangInstanceIdentifier.empty()).get();
         assertTrue(data instanceof ContainerNode);
-        assertEquals(0, ((ContainerNode) data).getValue().size());
+        assertEquals(0, ((ContainerNode) data).size());
     }
 
     @Test
@@ -434,7 +434,7 @@ public class Bug4454Test {
     private static void testLoop(final DataTreeSnapshot snapshot, final String first, final String second) {
         Optional<NormalizedNode<?, ?>> minMaxListRead = snapshot.readNode(MIN_MAX_LIST_PATH);
         assertTrue(minMaxListRead.isPresent());
-        assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 2);
+        assertEquals(2, ((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).size());
         UnmodifiableCollection<?> collectionChildren = (UnmodifiableCollection<?>) minMaxListRead.get().getValue();
 
         for (Object collectionChild : collectionChildren) {
index abe4acb82f0cabc1b800a77ecc85aac1fd612c37..42fef9cb99cb6d09e0782a8538aa37caf650649a 100644 (file)
@@ -120,7 +120,7 @@ public class ListConstraintsValidation {
         final DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
         final Optional<NormalizedNode<?, ?>> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_PATH);
         assertTrue(minMaxListRead.isPresent());
-        assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 2);
+        assertEquals(2, ((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).size());
     }
 
     @Test(expected = DataValidationFailedException.class)
@@ -151,7 +151,7 @@ public class ListConstraintsValidation {
         DataTreeSnapshot snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
         Optional<NormalizedNode<?, ?>> minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_PATH);
         assertTrue(minMaxListRead.isPresent());
-        assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 2);
+        assertEquals(2, ((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).size());
 
         modificationTree = inMemoryDataTree.takeSnapshot().newModification();
         modificationTree.write(gooPath, gooEntryNode);
@@ -164,7 +164,7 @@ public class ListConstraintsValidation {
         snapshotAfterCommit = inMemoryDataTree.takeSnapshot();
         minMaxListRead = snapshotAfterCommit.readNode(MIN_MAX_LIST_PATH);
         assertTrue(minMaxListRead.isPresent());
-        assertTrue(((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).getValue().size() == 3);
+        assertEquals(3, ((NormalizedNodeContainer<?, ?, ?>) minMaxListRead.get()).size());
 
         modificationTree = inMemoryDataTree.takeSnapshot().newModification();
 
@@ -209,7 +209,7 @@ public class ListConstraintsValidation {
         final Optional<NormalizedNodeContainer<?, ?, ?>> leafList = ((NormalizedNodeContainer) masterContainer.get())
                 .getChild(new NodeIdentifier(MIN_MAX_LEAF_LIST_QNAME));
         assertTrue(leafList.isPresent());
-        assertTrue(leafList.get().getValue().size() == 2);
+        assertEquals(2, leafList.get().size());
     }
 
     @Test