Bug 2327: Handle binary data in NormalizedNode streaming 97/12797/5
authortpantelis <tpanteli@brocade.com>
Wed, 12 Nov 2014 22:09:15 +0000 (17:09 -0500)
committertpantelis <tpanteli@brocade.com>
Sun, 18 Jan 2015 09:52:29 +0000 (04:52 -0500)
Also made optimization improvements to reuse primitive (using valueOf) and coded String
values (using intern) when read from the stream.

Also added a reusable StringBuilder instance for building qnames. After
use, the StringBuilder is cleared via the delete method. This
effectively resets the char count to 0. Previously, the
code used string concatenation which the compiler will translate to use
an imlicit StringBuilder. These changes avoid the implicit creation of a
StringBuilder instance each time which should reduce object churn.

Change-Id: Ic9c745d97d1b5eed2dd24bc5d252d05ac1355cbb
Signed-off-by: tpantelis <tpanteli@brocade.com>
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputStreamReader.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeOutputStreamWriter.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/ValueTypes.java
opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeStreamReaderWriterTest.java
opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/TestModel.java
opendaylight/md-sal/sal-clustering-commons/src/test/resources/odl-datastore-test.yang

index 9201a94..8cd428b 100644 (file)
@@ -12,6 +12,18 @@ package org.opendaylight.controller.cluster.datastore.node.utils.stream;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import org.opendaylight.controller.cluster.datastore.node.utils.QNameFactory;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.Node;
@@ -29,18 +41,6 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNo
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import java.io.DataInput;
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
 
 /**
  * NormalizedNodeInputStreamReader reads the byte stream and constructs the normalized node including its children nodes.
@@ -67,6 +67,8 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeStreamRead
     private NormalizedNodeAttrBuilder<NodeWithValue, Object,
                                       LeafSetEntryNode<Object>> leafSetEntryBuilder;
 
+    private final StringBuilder reusableStringBuilder = new StringBuilder(50);
+
     public NormalizedNodeInputStreamReader(InputStream stream) throws IOException {
         Preconditions.checkNotNull(stream);
         input = new DataInputStream(stream);
@@ -147,7 +149,6 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeStreamRead
 
             case NodeTypes.ANY_XML_NODE :
                 LOG.debug("Read xml node");
-                Node<?> value = (Node<?>) readObject();
                 return Builders.anyXmlBuilder().withValue((Node<?>) readObject()).build();
 
             case NodeTypes.MAP_NODE :
@@ -196,14 +197,16 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeStreamRead
         String namespace = readCodedString();
         String revision = readCodedString();
 
-        // Not using stringbuilder as compiler optimizes string concatenation of +
         String qName;
         if(!Strings.isNullOrEmpty(revision)) {
-            qName = "(" + namespace + REVISION_ARG + revision + ")" +localName;
+            qName = reusableStringBuilder.append('(').append(namespace).append(REVISION_ARG).
+                        append(revision).append(')').append(localName).toString();
         } else {
-            qName = "(" + namespace + ")" + localName;
+            qName = reusableStringBuilder.append('(').append(namespace).append(')').
+                        append(localName).toString();
         }
 
+        reusableStringBuilder.delete(0, reusableStringBuilder.length());
         return QNameFactory.create(qName);
     }
 
@@ -213,7 +216,7 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeStreamRead
         if(valueType == NormalizedNodeOutputStreamWriter.IS_CODE_VALUE) {
             return codedStringMap.get(input.readInt());
         } else if(valueType == NormalizedNodeOutputStreamWriter.IS_STRING_VALUE) {
-            String value = input.readUTF();
+            String value = input.readUTF().intern();
             codedStringMap.put(Integer.valueOf(codedStringMap.size()), value);
             return value;
         }
@@ -249,22 +252,22 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeStreamRead
                 return readObjSet();
 
             case ValueTypes.BOOL_TYPE :
-                return input.readBoolean();
+                return Boolean.valueOf(input.readBoolean());
 
             case ValueTypes.BYTE_TYPE :
-                return input.readByte();
+                return Byte.valueOf(input.readByte());
 
             case ValueTypes.INT_TYPE :
-                return input.readInt();
+                return Integer.valueOf(input.readInt());
 
             case ValueTypes.LONG_TYPE :
-                return input.readLong();
+                return Long.valueOf(input.readLong());
 
             case ValueTypes.QNAME_TYPE :
                 return readQName();
 
             case ValueTypes.SHORT_TYPE :
-                return input.readShort();
+                return Short.valueOf(input.readShort());
 
             case ValueTypes.STRING_TYPE :
                 return input.readUTF();
@@ -275,6 +278,11 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeStreamRead
             case ValueTypes.BIG_INTEGER_TYPE :
                 return new BigInteger(input.readUTF());
 
+            case ValueTypes.BINARY_TYPE :
+                byte[] bytes = new byte[input.readInt()];
+                input.readFully(bytes);
+                return bytes;
+
             case ValueTypes.YANG_IDENTIFIER_TYPE :
             return readYangInstanceIdentifier();
 
index 46768d5..c76a254 100644 (file)
@@ -12,11 +12,6 @@ package org.opendaylight.controller.cluster.datastore.node.utils.stream;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import java.io.DataOutput;
 import java.io.DataOutputStream;
 import java.io.IOException;
@@ -24,6 +19,11 @@ import java.io.OutputStream;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * NormalizedNodeOutputStreamWriter will be used by distributed datastore to send normalized node in
@@ -339,6 +339,11 @@ public class NormalizedNodeOutputStreamWriter implements NormalizedNodeStreamWri
             case ValueTypes.BITS_TYPE:
                 writeObjSet((Set<?>) value);
                 break;
+            case ValueTypes.BINARY_TYPE:
+                byte[] bytes = (byte[]) value;
+                output.writeInt(bytes.length);
+                output.write(bytes);
+                break;
             case ValueTypes.YANG_IDENTIFIER_TYPE:
                 writeYangInstanceIdentifier((YangInstanceIdentifier) value);
                 break;
index 80fa527..e75a454 100644 (file)
@@ -9,14 +9,13 @@
 package org.opendaylight.controller.cluster.datastore.node.utils.stream;
 
 import com.google.common.base.Preconditions;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 
 public class ValueTypes {
     public static final byte SHORT_TYPE = 1;
@@ -30,6 +29,7 @@ public class ValueTypes {
     public static final byte STRING_TYPE = 9;
     public static final byte BIG_INTEGER_TYPE = 10;
     public static final byte BIG_DECIMAL_TYPE = 11;
+    public static final byte BINARY_TYPE = 12;
 
     private static Map<Class<?>, Byte> types = new HashMap<>();
 
@@ -45,6 +45,7 @@ public class ValueTypes {
         types.put(Short.class, Byte.valueOf(SHORT_TYPE));
         types.put(BigInteger.class, Byte.valueOf(BIG_INTEGER_TYPE));
         types.put(BigDecimal.class, Byte.valueOf(BIG_DECIMAL_TYPE));
+        types.put(byte[].class, Byte.valueOf(BINARY_TYPE));
     }
 
     public static final byte getSerializableType(Object node){
index 8854fc7..f3df8f0 100644 (file)
@@ -17,13 +17,17 @@ import org.junit.Assert;
 import org.junit.Test;
 import org.opendaylight.controller.cluster.datastore.util.TestModel;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
 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.api.schema.stream.NormalizedNodeWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 public class NormalizedNodeStreamReaderWriterTest {
@@ -31,7 +35,7 @@ public class NormalizedNodeStreamReaderWriterTest {
     @Test
     public void testNormalizedNodeStreamReaderWriter() throws IOException {
 
-        testNormalizedNodeStreamReaderWriter(TestModel.createTestContainer());
+        testNormalizedNodeStreamReaderWriter(createTestContainer());
 
         QName toaster = QName.create("http://netconfcentral.org/ns/toaster","2009-11-20","toaster");
         QName darknessFactor = QName.create("http://netconfcentral.org/ns/toaster","2009-11-20","darknessFactor");
@@ -44,6 +48,25 @@ public class NormalizedNodeStreamReaderWriterTest {
                 withChild(toasterNode).build());
     }
 
+    private NormalizedNode<?, ?> createTestContainer() {
+        byte[] bytes1 = {1,2,3};
+        LeafSetEntryNode<Object> entry1 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
+                new YangInstanceIdentifier.NodeWithValue(TestModel.BINARY_LEAF_LIST_QNAME, bytes1)).
+                withValue(bytes1).build();
+
+        byte[] bytes2 = {};
+        LeafSetEntryNode<Object> entry2 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
+                new YangInstanceIdentifier.NodeWithValue(TestModel.BINARY_LEAF_LIST_QNAME, bytes2)).
+                withValue(bytes2).build();
+
+        return TestModel.createBaseTestContainerBuilder().
+                withChild(ImmutableLeafSetNodeBuilder.create().withNodeIdentifier(
+                        new YangInstanceIdentifier.NodeIdentifier(TestModel.BINARY_LEAF_LIST_QNAME)).
+                        withChild(entry1).withChild(entry2).build()).
+                withChild(ImmutableNodes.leafNode(TestModel.SOME_BINARY_DATE_QNAME, new byte[]{1,2,3,4})).
+                        build();
+    }
+
     private void testNormalizedNodeStreamReaderWriter(NormalizedNode<?, ?> input) throws IOException {
 
         byte[] byteData = null;
index d3abd38..8720f3b 100644 (file)
 
 package org.opendaylight.controller.cluster.datastore.util;
 
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
 import com.google.common.collect.ImmutableSet;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
@@ -36,18 +46,6 @@ import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
 
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry;
-import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
-import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
-
 public class TestModel {
 
   public static final QName TEST_QNAME = QName.create(
@@ -66,6 +64,7 @@ public class TestModel {
   public static final QName DESC_QNAME = QName.create(TEST_QNAME, "desc");
   public static final QName POINTER_QNAME = QName.create(TEST_QNAME, "pointer");
   public static final QName SOME_BINARY_DATE_QNAME = QName.create(TEST_QNAME, "some-binary-data");
+  public static final QName BINARY_LEAF_LIST_QNAME = QName.create(TEST_QNAME, "binary_leaf_list");
   public static final QName SOME_REF_QNAME = QName.create(TEST_QNAME,
       "some-ref");
   public static final QName MYIDENTITY_QNAME = QName.create(TEST_QNAME,
index a1fbc1f..c720d5e 100644 (file)
@@ -74,6 +74,10 @@ module odl-datastore-test {
             type uint8;
         }
 
+        leaf-list binary_leaf_list {
+            type binary;
+        }
+
         leaf pointer {
             type leafref {
                 path "/network-topology/topology/node/termination-point/tp-id";

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.