Optimize NodeIdentifier reading 79/82279/13
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 29 May 2019 10:10:52 +0000 (12:10 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 29 May 2019 18:05:08 +0000 (20:05 +0200)
NodeIdentifiers are just an alias for QName, which is heavily
reused. This patch adds a secondary cache for interpreting QNames
as NodeIdentifiers, with instance reuse.

This allows us to reduce the number of NodeIdentifier instances,
while not relying on NodeIdentifier.create() for the common lookup
case.

JIRA: CONTROLLER-1898
Change-Id: Ifa0c5d572f7d39da49707529c7ddd9c9f36f2dab
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/LithiumNormalizedNodeInputStreamReader.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/SodiumNormalizedNodeInputStreamReader.java

index 9f52355..3b4f2da 100755 (executable)
@@ -252,8 +252,7 @@ class LithiumNormalizedNodeInputStreamReader extends ForwardingDataInput impleme
         return new AugmentationIdentifier(readQNameSet());
     }
 
         return new AugmentationIdentifier(readQNameSet());
     }
 
-    private NodeIdentifier readNodeIdentifier() throws IOException {
-        // FIXME: we should have a cache for these, too
+    NodeIdentifier readNodeIdentifier() throws IOException {
         return new NodeIdentifier(readQName());
     }
 
         return new NodeIdentifier(readQName());
     }
 
index eb7e9f1..4890180 100644 (file)
@@ -7,14 +7,18 @@
  */
 package org.opendaylight.controller.cluster.datastore.node.utils.stream;
 
  */
 package org.opendaylight.controller.cluster.datastore.node.utils.stream;
 
+import static com.google.common.base.Verify.verify;
+
 import java.io.DataInput;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import java.io.DataInput;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 
 final class SodiumNormalizedNodeInputStreamReader extends LithiumNormalizedNodeInputStreamReader {
 
 final class SodiumNormalizedNodeInputStreamReader extends LithiumNormalizedNodeInputStreamReader {
+    private final ArrayList<NodeIdentifier> codedNodeIdentifiers = new ArrayList<>();
     private final List<AugmentationIdentifier> codedAugments = new ArrayList<>();
     private final List<QName> codedQNames = new ArrayList<>();
 
     private final List<AugmentationIdentifier> codedAugments = new ArrayList<>();
     private final List<QName> codedQNames = new ArrayList<>();
 
@@ -53,6 +57,52 @@ final class SodiumNormalizedNodeInputStreamReader extends LithiumNormalizedNodeI
         }
     }
 
         }
     }
 
+    @Override
+    NodeIdentifier readNodeIdentifier() throws IOException {
+        // NodeIdentifier rides on top of QName, with this method really saying 'interpret next QName as NodeIdentifier'
+        // to do that we inter-mingle with readQName()
+        final byte valueType = readByte();
+        switch (valueType) {
+            case TokenTypes.IS_QNAME_CODE:
+                return codedNodeIdentifier(readInt());
+            case TokenTypes.IS_QNAME_VALUE:
+                return rawNodeIdentifier();
+            default:
+                throw new IOException("Unhandled QName value type " + valueType);
+        }
+    }
+
+    private NodeIdentifier codedNodeIdentifier(final int code) throws IOException {
+        final NodeIdentifier existing = codedNodeIdentifiers.size() > code ? codedNodeIdentifiers.get(code) : null;
+        return existing != null ? existing : storeNodeIdentifier(code, codedQName(code));
+    }
+
+    private NodeIdentifier rawNodeIdentifier() throws IOException {
+        // Capture size before it incremented
+        final int code = codedQNames.size();
+        return storeNodeIdentifier(code, rawQName());
+    }
+
+    private NodeIdentifier storeNodeIdentifier(final int code, final QName qname) {
+        final NodeIdentifier ret = NodeIdentifier.create(qname);
+        final int size = codedNodeIdentifiers.size();
+
+        if (code >= size) {
+            // Null-fill others
+            codedNodeIdentifiers.ensureCapacity(code + 1);
+            for (int i = size; i < code; ++i) {
+                codedNodeIdentifiers.add(null);
+            }
+
+            codedNodeIdentifiers.add(ret);
+        } else {
+            final NodeIdentifier check = codedNodeIdentifiers.set(code, ret);
+            verify(check == null);
+        }
+
+        return ret;
+    }
+
     private QName codedQName(final int code) throws IOException {
         try {
             return codedQNames.get(code);
     private QName codedQName(final int code) throws IOException {
         try {
             return codedQNames.get(code);

©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.