Optimize NodeIdentifier reading
[controller.git] / opendaylight / md-sal / sal-clustering-commons / src / main / java / org / opendaylight / controller / cluster / datastore / node / utils / stream / SodiumNormalizedNodeInputStreamReader.java
1 /*
2  * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.cluster.datastore.node.utils.stream;
9
10 import static com.google.common.base.Verify.verify;
11
12 import java.io.DataInput;
13 import java.io.IOException;
14 import java.util.ArrayList;
15 import java.util.List;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
19
20 final class SodiumNormalizedNodeInputStreamReader extends LithiumNormalizedNodeInputStreamReader {
21     private final ArrayList<NodeIdentifier> codedNodeIdentifiers = new ArrayList<>();
22     private final List<AugmentationIdentifier> codedAugments = new ArrayList<>();
23     private final List<QName> codedQNames = new ArrayList<>();
24
25     SodiumNormalizedNodeInputStreamReader(final DataInput input) {
26         super(input);
27     }
28
29     @Override
30     public NormalizedNodeStreamVersion getVersion() throws IOException {
31         return NormalizedNodeStreamVersion.SODIUM;
32     }
33
34     @Override
35     QName readQName() throws IOException {
36         final byte valueType = readByte();
37         switch (valueType) {
38             case TokenTypes.IS_QNAME_CODE:
39                 return codedQName(readInt());
40             case TokenTypes.IS_QNAME_VALUE:
41                 return rawQName();
42             default:
43                 throw new IOException("Unhandled QName value type " + valueType);
44         }
45     }
46
47     @Override
48     AugmentationIdentifier readAugmentationIdentifier() throws IOException {
49         final byte valueType = readByte();
50         switch (valueType) {
51             case TokenTypes.IS_AUGMENT_CODE:
52                 return codecAugmentId(readInt());
53             case TokenTypes.IS_AUGMENT_VALUE:
54                 return rawAugmentId();
55             default:
56                 throw new IOException("Unhandled QName value type " + valueType);
57         }
58     }
59
60     @Override
61     NodeIdentifier readNodeIdentifier() throws IOException {
62         // NodeIdentifier rides on top of QName, with this method really saying 'interpret next QName as NodeIdentifier'
63         // to do that we inter-mingle with readQName()
64         final byte valueType = readByte();
65         switch (valueType) {
66             case TokenTypes.IS_QNAME_CODE:
67                 return codedNodeIdentifier(readInt());
68             case TokenTypes.IS_QNAME_VALUE:
69                 return rawNodeIdentifier();
70             default:
71                 throw new IOException("Unhandled QName value type " + valueType);
72         }
73     }
74
75     private NodeIdentifier codedNodeIdentifier(final int code) throws IOException {
76         final NodeIdentifier existing = codedNodeIdentifiers.size() > code ? codedNodeIdentifiers.get(code) : null;
77         return existing != null ? existing : storeNodeIdentifier(code, codedQName(code));
78     }
79
80     private NodeIdentifier rawNodeIdentifier() throws IOException {
81         // Capture size before it incremented
82         final int code = codedQNames.size();
83         return storeNodeIdentifier(code, rawQName());
84     }
85
86     private NodeIdentifier storeNodeIdentifier(final int code, final QName qname) {
87         final NodeIdentifier ret = NodeIdentifier.create(qname);
88         final int size = codedNodeIdentifiers.size();
89
90         if (code >= size) {
91             // Null-fill others
92             codedNodeIdentifiers.ensureCapacity(code + 1);
93             for (int i = size; i < code; ++i) {
94                 codedNodeIdentifiers.add(null);
95             }
96
97             codedNodeIdentifiers.add(ret);
98         } else {
99             final NodeIdentifier check = codedNodeIdentifiers.set(code, ret);
100             verify(check == null);
101         }
102
103         return ret;
104     }
105
106     private QName codedQName(final int code) throws IOException {
107         try {
108             return codedQNames.get(code);
109         } catch (IndexOutOfBoundsException e) {
110             throw new IOException("QName code " + code + " was not found", e);
111         }
112     }
113
114     private QName rawQName() throws IOException {
115         final QName qname = super.readQName();
116         codedQNames.add(qname);
117         return qname;
118     }
119
120     private AugmentationIdentifier codecAugmentId(final int code) throws IOException {
121         try {
122             return codedAugments.get(code);
123         } catch (IndexOutOfBoundsException e) {
124             throw new IOException("QName set code " + code + " was not found", e);
125         }
126     }
127
128     private AugmentationIdentifier rawAugmentId() throws IOException {
129         final AugmentationIdentifier aid = super.readAugmentationIdentifier();
130         codedAugments.add(aid);
131         return aid;
132     }
133 }

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