Rework AbstractNormalizedNodePruner 63/85563/1
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 14 May 2019 08:15:19 +0000 (10:15 +0200)
committerRobert Varga <nite@hq.sk>
Mon, 4 Nov 2019 16:49:52 +0000 (16:49 +0000)
This refactors NormalizedNodePruner to use
ReusableImmutableNormalizedNodeStreamWriter for creation of the
actual NormalizedNode tree.

It simplifies the implementation and allows the reuse of minor
optimizations like LeafInterner.

JIRA: CONTROLLER-1889
Change-Id: I93bd00bcff13245d808f7adf6122a6c20156e9fd
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
(cherry picked from commit bb86472bd5abf18630abe60eaf3f20becd013fed)

opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/AbstractNormalizedNodePruner.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/NormalizedNodeBuilderWrapper.java [deleted file]

index 03467f39cb37182b368368ac0f618ad50fad2d70..a6d8801d77b797f1cb850a73eb2c05dac8cd5ab5 100644 (file)
@@ -24,10 +24,10 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithV
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
-import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.ReusableImmutableNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -43,13 +43,28 @@ abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWrite
         CLOSED;
     }
 
+    @FunctionalInterface
+    private interface WriterMethod<T extends PathArgument> {
+
+        void apply(ReusableImmutableNormalizedNodeStreamWriter writer, T name) throws IOException;
+    }
+
+    @FunctionalInterface
+    private interface SizedWriterMethod<T extends PathArgument> {
+
+        void apply(ReusableImmutableNormalizedNodeStreamWriter writer, T name, int childSizeHint) throws IOException;
+    }
+
     private static final Logger LOG = LoggerFactory.getLogger(AbstractNormalizedNodePruner.class);
 
-    private final Deque<NormalizedNodeBuilderWrapper> stack = new ArrayDeque<>();
+    private final Deque<DataSchemaContextNode<?>> stack = new ArrayDeque<>();
+    private final ReusableImmutableNormalizedNodeStreamWriter delegate =
+            ReusableImmutableNormalizedNodeStreamWriter.create();
     private final DataSchemaContextTree tree;
 
     private DataSchemaContextNode<?> nodePathSchemaNode;
     private State state = State.UNITIALIZED;
+    private int unknown;
 
     // FIXME: package-private to support unguarded NormalizedNodePruner access
     NormalizedNode<?, ?> normalizedNode;
@@ -68,131 +83,136 @@ abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWrite
 
     final void initialize(final YangInstanceIdentifier nodePath) {
         nodePathSchemaNode = tree.findChild(nodePath).orElse(null);
+        unknown = 0;
         normalizedNode = null;
         stack.clear();
+        delegate.reset();
         state = State.OPEN;
     }
 
     @Override
-    public void startLeafNode(final NodeIdentifier name) {
-        addBuilder(Builders.leafBuilder().withNodeIdentifier(name), name);
+    public void startLeafNode(final NodeIdentifier name) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startLeafNode, name);
     }
 
     @Override
-    public void startLeafSet(final NodeIdentifier nodeIdentifier, final int count) {
-        addBuilder(Builders.leafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+    public void startLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startLeafSet, name, childSizeHint);
     }
 
     @Override
-    public void startOrderedLeafSet(final NodeIdentifier nodeIdentifier, final int str) {
-        addBuilder(Builders.orderedLeafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+    public void startOrderedLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startOrderedLeafSet, name, childSizeHint);
     }
 
     @Override
     public void startLeafSetEntryNode(final NodeWithValue<?> name) throws IOException {
-        addBuilder(Builders.leafSetEntryBuilder().withNodeIdentifier(name), name);
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startLeafSetEntryNode, name);
     }
 
     @Override
-    public void startContainerNode(final NodeIdentifier nodeIdentifier, final int count) {
-        addBuilder(Builders.containerBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+    public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startContainerNode, name, childSizeHint);
     }
 
     @Override
     public void startYangModeledAnyXmlNode(final NodeIdentifier nodeIdentifier, final int count) {
+        // FIXME: implement this
         throw new UnsupportedOperationException("Not implemented yet");
     }
 
     @Override
-    public void startUnkeyedList(final NodeIdentifier nodeIdentifier, final int count) {
-        addBuilder(Builders.unkeyedListBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+    public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startUnkeyedList, name, childSizeHint);
     }
 
     @Override
-    public void startUnkeyedListItem(final NodeIdentifier nodeIdentifier, final int count) {
-        addBuilder(Builders.unkeyedListEntryBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+    public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startUnkeyedListItem, name, childSizeHint);
     }
 
     @Override
-    public void startMapNode(final NodeIdentifier nodeIdentifier, final int count) {
-        addBuilder(Builders.mapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+    public void startMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startMapNode, name, childSizeHint);
     }
 
     @Override
-    public void startMapEntryNode(final NodeIdentifierWithPredicates nodeIdentifierWithPredicates, final int count) {
-        addBuilder(Builders.mapEntryBuilder().withNodeIdentifier(nodeIdentifierWithPredicates),
-                nodeIdentifierWithPredicates);
+    public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
+            throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startMapEntryNode, identifier, childSizeHint);
     }
 
     @Override
-    public void startOrderedMapNode(final NodeIdentifier nodeIdentifier, final int count) {
-        addBuilder(Builders.orderedMapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+    public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startOrderedMapNode, name, childSizeHint);
     }
 
     @Override
-    public void startChoiceNode(final NodeIdentifier nodeIdentifier, final int count) {
-        addBuilder(Builders.choiceBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
+    public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startChoiceNode, name, childSizeHint);
     }
 
     @Override
-    public void startAugmentationNode(final AugmentationIdentifier augmentationIdentifier) {
-        addBuilder(Builders.augmentationBuilder().withNodeIdentifier(augmentationIdentifier), augmentationIdentifier);
+    public void startAugmentationNode(final AugmentationIdentifier identifier) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startAugmentationNode, identifier);
     }
 
     @Override
-    public void startAnyxmlNode(final NodeIdentifier name) {
-        addBuilder(Builders.anyXmlBuilder().withNodeIdentifier(name), name);
+    public void startAnyxmlNode(final NodeIdentifier name) throws IOException {
+        enter(ReusableImmutableNormalizedNodeStreamWriter::startAnyxmlNode, name);
     }
 
     @Override
-    public void domSourceValue(final DOMSource value) {
-        setValue(value);
+    public void domSourceValue(final DOMSource value) throws IOException {
+        checkNotSealed();
+        if (unknown == 0) {
+            delegate.domSourceValue(value);
+        }
     }
 
     @Override
-    public void scalarValue(final Object value) {
-        setValue(value);
+    public void scalarValue(final Object value) throws IOException {
+        checkNotSealed();
+        if (unknown == 0) {
+            delegate.scalarValue(value);
+        }
     }
 
     @Override
-    public void endNode() {
+    public void endNode() throws IOException {
         checkNotSealed();
 
-        final NormalizedNodeBuilderWrapper child;
-        try {
-            child = stack.pop();
-        } catch (NoSuchElementException e) {
-            throw new IllegalStateException("endNode called on an empty stack", e);
-        }
-
-        if (child.getSchema() == null) {
-            LOG.debug("Schema not found for {}", child.identifier());
-            if (stack.isEmpty()) {
-                normalizedNode = null;
-                state = State.CLOSED;
+        if (unknown == 0) {
+            try {
+                stack.pop();
+            } catch (NoSuchElementException e) {
+                throw new IllegalStateException("endNode called on an empty stack", e);
+            }
+            delegate.endNode();
+        } else {
+            unknown--;
+            if (unknown != 0) {
+                // Still at unknown, do not attempt to create result
+                return;
             }
-            return;
         }
 
-        final NormalizedNode<?, ?> newNode = child.build();
-        final NormalizedNodeBuilderWrapper parent = stack.peek();
-        if (parent == null) {
-            normalizedNode = newNode;
+        if (stack.isEmpty()) {
+            normalizedNode = delegate.getResult();
             state = State.CLOSED;
-        } else {
-            parent.addChild(newNode);
         }
     }
 
     @Override
-    public void close() {
+    public void close() throws IOException {
         state = State.CLOSED;
         stack.clear();
+        delegate.close();
     }
 
     @Override
-    public void flush() {
-        // No-op
+    public void flush() throws IOException {
+        delegate.flush();
     }
 
     /**
@@ -210,27 +230,47 @@ abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWrite
         checkState(state == State.OPEN, "Illegal operation in state %s", state);
     }
 
-    private void setValue(final Object value) {
+    private boolean enter(final PathArgument name) {
         checkNotSealed();
-        final NormalizedNodeBuilderWrapper current = stack.peek();
-        checkState(current != null, "Attempted to set value %s while no node is open", value);
-        current.setValue(value);
-    }
 
-    private <T extends NormalizedNodeBuilder<?, ?, ?>> NormalizedNodeBuilderWrapper addBuilder(final T builder,
-            final PathArgument identifier) {
-        checkNotSealed();
+        if (unknown != 0) {
+            LOG.debug("Skipping child {} in unknown subtree", name);
+            unknown++;
+            return false;
+        }
 
-        final DataSchemaContextNode<?> schemaNode;
-        final NormalizedNodeBuilderWrapper parent = stack.peek();
+        final DataSchemaContextNode<?> schema;
+        final DataSchemaContextNode<?> parent = stack.peek();
         if (parent != null) {
-            schemaNode = parent.childSchema(identifier);
+            schema = parent.getChild(name);
         } else {
-            schemaNode = nodePathSchemaNode;
+            schema = nodePathSchemaNode;
         }
 
-        NormalizedNodeBuilderWrapper wrapper = new NormalizedNodeBuilderWrapper(builder, identifier, schemaNode);
-        stack.push(wrapper);
-        return wrapper;
+        if (schema == null) {
+            LOG.debug("Schema not found for {}", name);
+            unknown = 1;
+            return false;
+        }
+
+        stack.push(schema);
+        final DataSchemaNode dataSchema = schema.getDataSchemaNode();
+        if (dataSchema != null) {
+            delegate.nextDataSchemaNode(dataSchema);
+        }
+        return true;
+    }
+
+    private <A extends PathArgument> void enter(final WriterMethod<A> method, final A name) throws IOException {
+        if (enter(name)) {
+            method.apply(delegate, name);
+        }
+    }
+
+    private <A extends PathArgument> void enter(final SizedWriterMethod<A> method, final A name, final int size)
+            throws IOException {
+        if (enter(name)) {
+            method.apply(delegate, name, size);
+        }
     }
 }
diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/NormalizedNodeBuilderWrapper.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/transformer/NormalizedNodeBuilderWrapper.java
deleted file mode 100644 (file)
index 385376c..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2015 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.cluster.datastore.node.utils.transformer;
-
-import static com.google.common.base.Preconditions.checkState;
-import static java.util.Objects.requireNonNull;
-
-import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
-import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
-
-final class NormalizedNodeBuilderWrapper {
-    @SuppressWarnings("rawtypes")
-    private final NormalizedNodeBuilder builder;
-    private final PathArgument identifier;
-    private final DataSchemaContextNode<?> schemaNode;
-
-    NormalizedNodeBuilderWrapper(final NormalizedNodeBuilder<?, ?, ?> builder,
-            final PathArgument identifier, final @Nullable DataSchemaContextNode<?> schemaNode) {
-        this.builder = requireNonNull(builder);
-        this.identifier = requireNonNull(identifier);
-        this.schemaNode = schemaNode;
-    }
-
-    PathArgument identifier() {
-        return identifier;
-    }
-
-    @Nullable DataSchemaContextNode<?> getSchema() {
-        return schemaNode;
-    }
-
-    @Nullable DataSchemaContextNode<?> childSchema(final PathArgument child) {
-        if (schemaNode == null) {
-            return null;
-        }
-
-        checkState(builder instanceof NormalizedNodeContainerBuilder,
-            "Attempted to lookup child %s in non-container %s", schemaNode);
-        return schemaNode.getChild(child);
-    }
-
-    NormalizedNode<?, ?> build() {
-        return builder.build();
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    void addChild(final NormalizedNode<?, ?> child) {
-        checkState(builder instanceof NormalizedNodeContainerBuilder,
-            "Attempted to add child %s to non-container builder %s", child, builder);
-        ((NormalizedNodeContainerBuilder) builder).addChild(child);
-    }
-
-    @SuppressWarnings("unchecked")
-    void setValue(final Object value) {
-        checkState(!(builder instanceof NormalizedNodeContainerBuilder),
-            "Attempted to set value %s on container builder %s", value, builder);
-        builder.withValue(value);
-    }
-}