tmf: fix potential bug when selecting trace types in import wizard
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / backends / historytree / HTInterval.java
CommitLineData
a52fde77 1/*******************************************************************************
61759503 2 * Copyright (c) 2012, 2013 Ericsson
a52fde77
AM
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
98107b3f 5 *
a52fde77
AM
6 * All rights reserved. This program and the accompanying materials are
7 * made available under the terms of the Eclipse Public License v1.0 which
8 * accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
98107b3f 10 *
a52fde77
AM
11 *******************************************************************************/
12
f9a76cac 13package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree;
a52fde77
AM
14
15import java.io.IOException;
16import java.nio.ByteBuffer;
17
6d08acca
AM
18import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
19import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
a52fde77 20import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
a52fde77 21import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
a52fde77
AM
22import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
23
24/**
25 * The interval component, which will be contained in a node of the History
26 * Tree.
98107b3f 27 *
a52fde77 28 * @author alexmont
98107b3f 29 *
a52fde77
AM
30 */
31final class HTInterval implements ITmfStateInterval, Comparable<HTInterval> {
32
b67a2540
AM
33 private static final String errMsg = "Invalid interval data. Maybe your file is corrupt?"; //$NON-NLS-1$
34
35 /* 'Byte' equivalent for state values types */
36 private static final byte TYPE_NULL = -1;
37 private static final byte TYPE_INTEGER = 0;
38 private static final byte TYPE_STRING = 1;
1cbf1a19 39 private static final byte TYPE_LONG = 2;
b67a2540 40
a52fde77
AM
41 private final long start;
42 private final long end;
43 private final int attribute;
44 private final TmfStateValue sv;
45
46 /*
47 * Size of the strings section entry used by this interval (= 0 if not used)
48 */
49 private final int stringsEntrySize;
50
51 /**
52 * Standard constructor
98107b3f 53 *
a52fde77
AM
54 * @param intervalStart
55 * @param intervalEnd
56 * @param attribute
57 * @param value
58 * @throws TimeRangeException
59 */
60 HTInterval(long intervalStart, long intervalEnd, int attribute,
61 TmfStateValue value) throws TimeRangeException {
62 if (intervalStart > intervalEnd) {
63 throw new TimeRangeException();
64 }
65
66 this.start = intervalStart;
67 this.end = intervalEnd;
68 this.attribute = attribute;
69 this.sv = value;
70 this.stringsEntrySize = computeStringsEntrySize();
71 }
72
73 /**
74 * Reader constructor. Builds the interval using an already-allocated
75 * ByteBuffer, which normally comes from a NIO FileChannel.
98107b3f 76 *
a52fde77
AM
77 * @param buffer
78 * The ByteBuffer from which to read the information
79 * @throws IOException
80 */
81 final static HTInterval readFrom(ByteBuffer buffer) throws IOException {
82 HTInterval interval;
83 long intervalStart, intervalEnd;
84 int attribute;
85 TmfStateValue value;
86 int valueOrOffset, valueSize, res;
87 byte valueType;
88 byte array[];
89
90 /* Read the Data Section entry */
91 intervalStart = buffer.getLong();
92 intervalEnd = buffer.getLong();
93 attribute = buffer.getInt();
94
95 /* Read the 'type' of the value, then react accordingly */
96 valueType = buffer.get();
b67a2540
AM
97 valueOrOffset = buffer.getInt();
98 switch (valueType) {
a52fde77 99
b67a2540
AM
100 case TYPE_NULL:
101 value = TmfStateValue.nullValue();
102 break;
a52fde77 103
b67a2540
AM
104 case TYPE_INTEGER:
105 /* "ValueOrOffset" is the straight value */
106 value = TmfStateValue.newValueInt(valueOrOffset);
107 break;
108
109 case TYPE_STRING:
110 /* Go read the matching entry in the Strings section of the block */
a52fde77
AM
111 buffer.mark();
112 buffer.position(valueOrOffset);
113
114 /* the first byte = the size to read */
115 valueSize = buffer.get();
116
117 /*
118 * Careful though, 'valueSize' is the total size of the entry,
119 * including the 'size' byte at the start and end (0'ed) byte at the
120 * end. Here we want 'array' to only contain the real payload of the
121 * value.
122 */
123 array = new byte[valueSize - 2];
124 buffer.get(array);
125 value = TmfStateValue.newValueString(new String(array));
126
127 /* Confirm the 0'ed byte at the end */
128 res = buffer.get();
129 if (res != 0) {
b67a2540 130 throw new IOException(errMsg);
a52fde77
AM
131 }
132
1cbf1a19
FR
133 /*
134 * Restore the file pointer's position (so we can read the next
135 * interval)
136 */
137 buffer.reset();
138 break;
139
140 case TYPE_LONG:
141 /* Go read the matching entry in the Strings section of the block */
142 buffer.mark();
143 buffer.position(valueOrOffset);
144 value = TmfStateValue.newValueLong(buffer.getLong());
145
a52fde77
AM
146 /*
147 * Restore the file pointer's position (so we can read the next
148 * interval)
149 */
150 buffer.reset();
b67a2540
AM
151 break;
152 default:
153 /* Unknown data, better to not make anything up... */
154 throw new IOException(errMsg);
a52fde77
AM
155 }
156
157 try {
b67a2540 158 interval = new HTInterval(intervalStart, intervalEnd, attribute, value);
a52fde77 159 } catch (TimeRangeException e) {
b67a2540 160 throw new IOException(errMsg);
a52fde77
AM
161 }
162 return interval;
163 }
164
165 /**
166 * Antagonist of the previous constructor, write the Data entry
167 * corresponding to this interval in a ByteBuffer (mapped to a block in the
168 * history-file, hopefully)
98107b3f 169 *
a52fde77
AM
170 * @param buffer
171 * The already-allocated ByteBuffer corresponding to a SHT Node
172 * @param endPosOfStringEntry
173 * The initial (before calling this function for this interval)
174 * position of the Strings Entry for this node. This will change
175 * from one call to the other if we're writing String
176 * StateValues.
177 * @return The size of the Strings Entry that was written, if any.
178 */
179 int writeInterval(ByteBuffer buffer, int endPosOfStringEntry) {
a52fde77
AM
180 buffer.putLong(start);
181 buffer.putLong(end);
182 buffer.putInt(attribute);
b67a2540 183 buffer.put(getByteFromType(sv.getType()));
a52fde77 184
1cbf1a19 185 switch (getByteFromType(sv.getType())) {
a52fde77 186
1cbf1a19
FR
187 case TYPE_NULL:
188 case TYPE_INTEGER:
6a4fd492
AM
189 /* We write the 'valueOffset' field as a straight value. In the case
190 * of a null value, it will be unboxed as -1 */
191 try {
192 buffer.putInt(sv.unboxInt());
193 } catch (StateValueTypeException e) {
194 /*
195 * This should not happen, since the value told us it was of
196 * type Null or Integer (corrupted value?)
197 */
198 e.printStackTrace();
a52fde77 199 }
9177eb74 200 break;
a52fde77 201
1cbf1a19 202 case TYPE_STRING:
9177eb74
AM
203 byte[] byteArrayToWrite;
204 try {
205 byteArrayToWrite = sv.unboxStr().getBytes();
206 } catch (StateValueTypeException e1) {
207 /* Should not happen, we're in a switch/case for string type */
208 throw new RuntimeException();
209 }
1cbf1a19
FR
210
211 /* we use the valueOffset as an offset. */
9177eb74 212 buffer.putInt(endPosOfStringEntry - stringsEntrySize);
1cbf1a19 213 buffer.mark();
9177eb74 214 buffer.position(endPosOfStringEntry - stringsEntrySize);
1cbf1a19
FR
215
216 /*
217 * write the Strings entry (1st byte = size, then the bytes, then the 0)
218 */
9177eb74 219 buffer.put((byte) stringsEntrySize);
1cbf1a19
FR
220 buffer.put(byteArrayToWrite);
221 buffer.put((byte) 0);
222 assert (buffer.position() == endPosOfStringEntry);
223 buffer.reset();
9177eb74 224 break;
1cbf1a19
FR
225
226 case TYPE_LONG:
1cbf1a19 227 /* we use the valueOffset as an offset. */
9177eb74 228 buffer.putInt(endPosOfStringEntry - stringsEntrySize);
1cbf1a19 229 buffer.mark();
9177eb74 230 buffer.position(endPosOfStringEntry - stringsEntrySize);
1cbf1a19
FR
231
232 /*
233 * write the Long in the Strings section
234 */
235 try {
236 buffer.putLong(sv.unboxLong());
237 } catch (StateValueTypeException e) {
238 /*
239 * This should not happen, since the value told us it was of
240 * type Long (corrupted value?)
241 */
242 e.printStackTrace();
243 }
244 assert (buffer.position() == endPosOfStringEntry);
245 buffer.reset();
9177eb74 246 break;
1cbf1a19
FR
247
248 default:
9177eb74 249 break;
a52fde77 250 }
9177eb74 251 return stringsEntrySize;
a52fde77
AM
252 }
253
254 @Override
255 public long getStartTime() {
256 return start;
257 }
258
259 @Override
260 public long getEndTime() {
261 return end;
262 }
263
eaad89a0
AM
264 @Override
265 public long getViewerEndTime() {
266 return end + 1;
267 }
268
a52fde77
AM
269 @Override
270 public int getAttribute() {
271 return attribute;
272 }
273
274 @Override
275 public ITmfStateValue getStateValue() {
276 return sv;
277 }
278
279 @Override
280 public boolean intersects(long timestamp) {
281 if (start <= timestamp) {
282 if (end >= timestamp) {
283 return true;
284 }
285 }
286 return false;
287 }
288
289 int getStringsEntrySize() {
290 return stringsEntrySize;
291 }
292
293 /**
294 * Total serialized size of this interval
98107b3f 295 *
a52fde77
AM
296 * @return
297 */
298 int getIntervalSize() {
299 return stringsEntrySize + HTNode.getDataEntrySize();
300 }
301
302 private int computeStringsEntrySize() {
9177eb74
AM
303 switch(sv.getType()) {
304 case NULL:
305 case INTEGER:
306 /* Those don't use the strings section at all */
a52fde77 307 return 0;
9177eb74
AM
308 case LONG:
309 /* The value's bytes are written directly into the strings section */
310 return 8;
311 case STRING:
312 try {
313 /* String's length + 2 (1 byte for size, 1 byte for \0 at the end */
314 return sv.unboxStr().getBytes().length + 2;
315 } catch (StateValueTypeException e) {
316 /* We're inside a switch/case for the string type, can't happen */
317 throw new RuntimeException();
318 }
319 default:
320 /* It's very important that we know how to write the state value in
321 * the file!! */
322 throw new RuntimeException();
1b558482 323 }
a52fde77
AM
324 }
325
326 /**
327 * Compare the END TIMES of different intervals. This is used to sort the
328 * intervals when we close down a node.
329 */
330 @Override
331 public int compareTo(HTInterval other) {
332 if (this.end < other.end) {
333 return -1;
334 } else if (this.end > other.end) {
335 return 1;
336 } else {
337 return 0;
338 }
339 }
1b558482 340
ab604305
AM
341 @Override
342 public boolean equals(Object other) {
343 if (other instanceof HTInterval) {
344 if (this.compareTo((HTInterval) other) == 0) {
345 return true;
346 }
347 }
348 return false;
349 }
350
351 @Override
352 public int hashCode() {
353 return super.hashCode();
354 }
1b558482
AM
355
356 @Override
357 public String toString() {
358 /* Only for debug, should not be externalized */
98107b3f
AM
359 StringBuilder sb = new StringBuilder();
360 sb.append('[');
361 sb.append(start);
362 sb.append(", "); //$NON-NLS-1$
363 sb.append(end);
364 sb.append(']');
365
366 sb.append(", attribute = "); //$NON-NLS-1$
367 sb.append(attribute);
368
369 sb.append(", value = "); //$NON-NLS-1$
370 sb.append(sv.toString());
371
372 return sb.toString();
1b558482 373 }
b67a2540
AM
374
375 /**
376 * Here we determine how state values "types" are written in the 8-bit
377 * field that indicates the value type in the file.
378 */
379 private static byte getByteFromType(ITmfStateValue.Type type) {
380 switch(type) {
381 case NULL:
382 return TYPE_NULL;
383 case INTEGER:
384 return TYPE_INTEGER;
385 case STRING:
386 return TYPE_STRING;
1cbf1a19
FR
387 case LONG:
388 return TYPE_LONG;
b67a2540
AM
389 default:
390 /* Should not happen if the switch is fully covered */
391 throw new RuntimeException();
392 }
393 }
a52fde77 394}
This page took 0.05849 seconds and 5 git commands to generate.