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