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 9f523555bb5a640498dce27023145511e9f2e106..3b4f2dad05d1170a9cc96fef48b096693e2e5dea 100755 (executable)
@@ -252,8 +252,7 @@ class LithiumNormalizedNodeInputStreamReader extends ForwardingDataInput impleme
         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());
     }
 
index eb7e9f1b8acb363f56ccfb6a3810700f364c23df..48901801155b7d8f6695303b7f715d8055d715ea 100644 (file)
@@ -7,14 +7,18 @@
  */
 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 org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 
 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<>();
 
@@ -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);