Commit | Line | Data |
---|---|---|
a52fde77 | 1 | /******************************************************************************* |
b2ca67ca | 2 | * Copyright (c) 2010, 2016 Ericsson, École Polytechnique de Montréal, and others |
cb42195c | 3 | * |
a52fde77 AM |
4 | * All rights reserved. This program and the accompanying materials are |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
cb42195c | 8 | * |
bb7f92ce FW |
9 | * Contributors: |
10 | * Alexandre Montplaisir - Initial API and implementation | |
11 | * Florian Wininger - Add Extension and Leaf Node | |
a52fde77 AM |
12 | *******************************************************************************/ |
13 | ||
f4baf640 | 14 | package org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.classic; |
a52fde77 AM |
15 | |
16 | import java.nio.ByteBuffer; | |
b2ca67ca | 17 | import java.util.Arrays; |
88598bff LPD |
18 | import java.util.Collection; |
19 | import java.util.Collections; | |
62197b87 | 20 | import java.util.concurrent.locks.ReentrantReadWriteLock; |
a52fde77 | 21 | |
f4baf640 GB |
22 | import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.HTConfig; |
23 | import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.HTNode; | |
24 | import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.ParentNode; | |
88598bff | 25 | import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException; |
f4baf640 | 26 | |
a52fde77 AM |
27 | /** |
28 | * A Core node is a first-level node of a History Tree which is not a leaf node. | |
cb42195c | 29 | * |
a52fde77 | 30 | * It extends HTNode by adding support for child nodes, and also extensions. |
cb42195c | 31 | * |
ffd0aa67 | 32 | * @author Alexandre Montplaisir |
a52fde77 | 33 | */ |
f4baf640 | 34 | public final class CoreNode extends ParentNode { |
a52fde77 | 35 | |
cb42195c | 36 | /** Nb. of children this node has */ |
a52fde77 AM |
37 | private int nbChildren; |
38 | ||
cb42195c | 39 | /** Seq. numbers of the children nodes (size = MAX_NB_CHILDREN) */ |
a52fde77 AM |
40 | private int[] children; |
41 | ||
cb42195c | 42 | /** Start times of each of the children (size = MAX_NB_CHILDREN) */ |
a52fde77 AM |
43 | private long[] childStart; |
44 | ||
cb42195c | 45 | /** Seq number of this node's extension. -1 if none */ |
62197b87 AM |
46 | private volatile int extension = -1; |
47 | ||
48 | /** | |
49 | * Lock used to gate the accesses to the children arrays. Meant to be a | |
50 | * different lock from the one in {@link HTNode}. | |
51 | */ | |
52 | private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(false); | |
a52fde77 AM |
53 | |
54 | /** | |
55 | * Initial constructor. Use this to initialize a new EMPTY node. | |
cb42195c | 56 | * |
ffd0aa67 EB |
57 | * @param config |
58 | * Configuration of the History Tree | |
a52fde77 AM |
59 | * @param seqNumber |
60 | * The (unique) sequence number assigned to this particular node | |
61 | * @param parentSeqNumber | |
62 | * The sequence number of this node's parent node | |
63 | * @param start | |
64 | * The earliest timestamp stored in this node | |
65 | */ | |
bb7f92ce | 66 | public CoreNode(HTConfig config, int seqNumber, int parentSeqNumber, |
a52fde77 | 67 | long start) { |
ffd0aa67 | 68 | super(config, seqNumber, parentSeqNumber, start); |
a52fde77 | 69 | this.nbChildren = 0; |
ffd0aa67 | 70 | int size = config.getMaxChildren(); |
a52fde77 AM |
71 | |
72 | /* | |
73 | * We instantiate the two following arrays at full size right away, | |
74 | * since we want to reserve that space in the node's header. | |
75 | * "this.nbChildren" will tell us how many relevant entries there are in | |
76 | * those tables. | |
77 | */ | |
cb42195c AM |
78 | this.children = new int[size]; |
79 | this.childStart = new long[size]; | |
a52fde77 AM |
80 | } |
81 | ||
82 | @Override | |
62197b87 | 83 | protected void readSpecificHeader(ByteBuffer buffer) { |
ffd0aa67 | 84 | int size = getConfig().getMaxChildren(); |
a52fde77 AM |
85 | |
86 | extension = buffer.getInt(); | |
87 | nbChildren = buffer.getInt(); | |
88 | ||
cb42195c AM |
89 | children = new int[size]; |
90 | for (int i = 0; i < nbChildren; i++) { | |
a52fde77 AM |
91 | children[i] = buffer.getInt(); |
92 | } | |
cb42195c | 93 | for (int i = nbChildren; i < size; i++) { |
a52fde77 AM |
94 | buffer.getInt(); |
95 | } | |
96 | ||
cb42195c AM |
97 | this.childStart = new long[size]; |
98 | for (int i = 0; i < nbChildren; i++) { | |
a52fde77 AM |
99 | childStart[i] = buffer.getLong(); |
100 | } | |
cb42195c | 101 | for (int i = nbChildren; i < size; i++) { |
a52fde77 AM |
102 | buffer.getLong(); |
103 | } | |
104 | } | |
105 | ||
106 | @Override | |
62197b87 | 107 | protected void writeSpecificHeader(ByteBuffer buffer) { |
ffd0aa67 | 108 | int size = getConfig().getMaxChildren(); |
a52fde77 AM |
109 | |
110 | buffer.putInt(extension); | |
111 | buffer.putInt(nbChildren); | |
112 | ||
113 | /* Write the "children's seq number" array */ | |
cb42195c | 114 | for (int i = 0; i < nbChildren; i++) { |
a52fde77 AM |
115 | buffer.putInt(children[i]); |
116 | } | |
cb42195c | 117 | for (int i = nbChildren; i < size; i++) { |
a52fde77 AM |
118 | buffer.putInt(0); |
119 | } | |
120 | ||
121 | /* Write the "children's start times" array */ | |
cb42195c | 122 | for (int i = 0; i < nbChildren; i++) { |
a52fde77 AM |
123 | buffer.putLong(childStart[i]); |
124 | } | |
cb42195c | 125 | for (int i = nbChildren; i < size; i++) { |
a52fde77 AM |
126 | buffer.putLong(0); |
127 | } | |
128 | } | |
129 | ||
f4baf640 | 130 | @Override |
8d47cc34 | 131 | public int getNbChildren() { |
62197b87 | 132 | rwl.readLock().lock(); |
88598bff LPD |
133 | try { |
134 | return nbChildren; | |
135 | } finally { | |
136 | rwl.readLock().unlock(); | |
137 | } | |
a52fde77 AM |
138 | } |
139 | ||
f4baf640 | 140 | @Override |
8d47cc34 | 141 | public int getChild(int index) { |
62197b87 AM |
142 | rwl.readLock().lock(); |
143 | try { | |
144 | return children[index]; | |
145 | } finally { | |
146 | rwl.readLock().unlock(); | |
147 | } | |
a52fde77 AM |
148 | } |
149 | ||
f4baf640 | 150 | @Override |
8d47cc34 | 151 | public int getLatestChild() { |
62197b87 AM |
152 | rwl.readLock().lock(); |
153 | try { | |
154 | return children[nbChildren - 1]; | |
155 | } finally { | |
156 | rwl.readLock().unlock(); | |
157 | } | |
a52fde77 AM |
158 | } |
159 | ||
f4baf640 | 160 | @Override |
8d47cc34 | 161 | public long getChildStart(int index) { |
62197b87 AM |
162 | rwl.readLock().lock(); |
163 | try { | |
164 | return childStart[index]; | |
165 | } finally { | |
166 | rwl.readLock().unlock(); | |
167 | } | |
a52fde77 AM |
168 | } |
169 | ||
8d47cc34 AM |
170 | /** |
171 | * Get the sequence number of the extension to this node (if there is one). | |
172 | * | |
173 | * @return The sequence number of the extended node. '-1' is returned if | |
174 | * there is no extension node. | |
175 | */ | |
176 | public int getExtensionSequenceNumber() { | |
88598bff LPD |
177 | rwl.readLock().lock(); |
178 | try { | |
179 | return extension; | |
180 | } finally { | |
181 | rwl.readLock().unlock(); | |
182 | } | |
a52fde77 AM |
183 | } |
184 | ||
f4baf640 | 185 | @Override |
bb7f92ce | 186 | public void linkNewChild(HTNode childNode) { |
62197b87 AM |
187 | rwl.writeLock().lock(); |
188 | try { | |
f4baf640 GB |
189 | if (nbChildren >= getConfig().getMaxChildren()) { |
190 | throw new IllegalStateException("Asked to link another child but parent already has maximum number of children"); //$NON-NLS-1$ | |
191 | } | |
a52fde77 | 192 | |
62197b87 AM |
193 | children[nbChildren] = childNode.getSequenceNumber(); |
194 | childStart[nbChildren] = childNode.getNodeStart(); | |
195 | nbChildren++; | |
196 | ||
197 | } finally { | |
198 | rwl.writeLock().unlock(); | |
199 | } | |
a52fde77 AM |
200 | } |
201 | ||
88598bff LPD |
202 | @Override |
203 | public Collection<Integer> selectNextChildren(long t) throws TimeRangeException { | |
204 | if (t < getNodeStart() || (isOnDisk() && t > getNodeEnd())) { | |
205 | throw new TimeRangeException("Requesting children outside the node's range: " + t); //$NON-NLS-1$ | |
206 | } | |
207 | rwl.readLock().lock(); | |
208 | try { | |
209 | int potentialNextSeqNb = -1; | |
210 | for (int i = 0; i < nbChildren; i++) { | |
211 | if (t >= childStart[i]) { | |
212 | potentialNextSeqNb = children[i]; | |
213 | } else { | |
214 | break; | |
215 | } | |
216 | } | |
217 | ||
218 | if (potentialNextSeqNb == -1) { | |
219 | throw new IllegalStateException("No next child node found"); //$NON-NLS-1$ | |
220 | } | |
221 | return Collections.singleton(potentialNextSeqNb); | |
222 | } finally { | |
223 | rwl.readLock().unlock(); | |
224 | } | |
225 | } | |
226 | ||
a52fde77 | 227 | @Override |
bb7f92ce FW |
228 | public NodeType getNodeType() { |
229 | return NodeType.CORE; | |
a52fde77 AM |
230 | } |
231 | ||
232 | @Override | |
62197b87 | 233 | protected int getSpecificHeaderSize() { |
ffd0aa67 | 234 | int maxChildren = getConfig().getMaxChildren(); |
cb42195c | 235 | int specificSize = |
d0ed4962 LPD |
236 | Integer.BYTES /* 1x int (extension node) */ |
237 | + Integer.BYTES /* 1x int (nbChildren) */ | |
a52fde77 AM |
238 | |
239 | /* MAX_NB * int ('children' table) */ | |
d0ed4962 | 240 | + Integer.BYTES * maxChildren |
a52fde77 AM |
241 | |
242 | /* MAX_NB * Timevalue ('childStart' table) */ | |
d0ed4962 | 243 | + Long.BYTES * maxChildren; |
a52fde77 | 244 | |
62197b87 | 245 | return specificSize; |
a52fde77 AM |
246 | } |
247 | ||
248 | @Override | |
8d47cc34 | 249 | public String toStringSpecific() { |
a52fde77 | 250 | /* Only used for debugging, shouldn't be externalized */ |
b2ca67ca PT |
251 | return String.format("Core Node, %d children %s", //$NON-NLS-1$ |
252 | nbChildren, Arrays.toString(Arrays.copyOf(children, nbChildren))); | |
a52fde77 AM |
253 | } |
254 | ||
255 | } |