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