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