From d0bfebae1d8f056220bc2f5b043f1f13b3b8d4e6 Mon Sep 17 00:00:00 2001 From: tpantelis Date: Wed, 12 Nov 2014 17:09:15 -0500 Subject: [PATCH] Bug 2327: Handle binary data in NormalizedNode streaming 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 --- .../NormalizedNodeInputStreamReader.java | 52 +++++++++++-------- .../NormalizedNodeOutputStreamWriter.java | 15 ++++-- .../node/utils/stream/ValueTypes.java | 7 +-- .../NormalizedNodeStreamReaderWriterTest.java | 25 ++++++++- .../cluster/datastore/util/TestModel.java | 23 ++++---- .../test/resources/odl-datastore-test.yang | 4 ++ 6 files changed, 83 insertions(+), 43 deletions(-) diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputStreamReader.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputStreamReader.java index 9201a94de3..8cd428bdcc 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputStreamReader.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputStreamReader.java @@ -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> 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(); diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeOutputStreamWriter.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeOutputStreamWriter.java index 46768d5112..c76a254b53 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeOutputStreamWriter.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeOutputStreamWriter.java @@ -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; diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/ValueTypes.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/ValueTypes.java index 80fa527b46..e75a454d39 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/ValueTypes.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/ValueTypes.java @@ -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, 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){ diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeStreamReaderWriterTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeStreamReaderWriterTest.java index 8854fc73b5..f3df8f0c57 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeStreamReaderWriterTest.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeStreamReaderWriterTest.java @@ -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 entry1 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier( + new YangInstanceIdentifier.NodeWithValue(TestModel.BINARY_LEAF_LIST_QNAME, bytes1)). + withValue(bytes1).build(); + + byte[] bytes2 = {}; + LeafSetEntryNode 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; diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/TestModel.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/TestModel.java index d3abd38153..8720f3bd88 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/TestModel.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/TestModel.java @@ -10,7 +10,17 @@ 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, diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/resources/odl-datastore-test.yang b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/odl-datastore-test.yang index a1fbc1fdad..c720d5e0cd 100644 --- a/opendaylight/md-sal/sal-clustering-commons/src/test/resources/odl-datastore-test.yang +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/odl-datastore-test.yang @@ -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"; -- 2.36.6