49100da9b3b1aa6d4610e4450d065aeeadf56fc7
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / backends / historytree / HTInterval.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Ericsson
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
5 *
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
10 *
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree;
14
15 import java.io.IOException;
16 import java.nio.ByteBuffer;
17
18 import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
19 import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
20 import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
21 import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
22 import 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.
27 *
28 * @author alexmont
29 *
30 */
31 final class HTInterval implements ITmfStateInterval, Comparable<HTInterval> {
32
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;
39 private static final byte TYPE_LONG = 2;
40
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
53 *
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.
76 *
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();
97 valueOrOffset = buffer.getInt();
98 switch (valueType) {
99
100 case TYPE_NULL:
101 value = TmfStateValue.nullValue();
102 break;
103
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 */
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) {
130 throw new IOException(errMsg);
131 }
132
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
146 /*
147 * Restore the file pointer's position (so we can read the next
148 * interval)
149 */
150 buffer.reset();
151 break;
152 default:
153 /* Unknown data, better to not make anything up... */
154 throw new IOException(errMsg);
155 }
156
157 try {
158 interval = new HTInterval(intervalStart, intervalEnd, attribute, value);
159 } catch (TimeRangeException e) {
160 throw new IOException(errMsg);
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)
169 *
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) {
180 buffer.putLong(start);
181 buffer.putLong(end);
182 buffer.putInt(attribute);
183 buffer.put(getByteFromType(sv.getType()));
184
185 switch (getByteFromType(sv.getType())) {
186
187 case TYPE_NULL:
188 case TYPE_INTEGER:
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();
199 }
200 break;
201
202 case TYPE_STRING:
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 }
210
211 /* we use the valueOffset as an offset. */
212 buffer.putInt(endPosOfStringEntry - stringsEntrySize);
213 buffer.mark();
214 buffer.position(endPosOfStringEntry - stringsEntrySize);
215
216 /*
217 * write the Strings entry (1st byte = size, then the bytes, then the 0)
218 */
219 buffer.put((byte) stringsEntrySize);
220 buffer.put(byteArrayToWrite);
221 buffer.put((byte) 0);
222 assert (buffer.position() == endPosOfStringEntry);
223 buffer.reset();
224 break;
225
226 case TYPE_LONG:
227 /* we use the valueOffset as an offset. */
228 buffer.putInt(endPosOfStringEntry - stringsEntrySize);
229 buffer.mark();
230 buffer.position(endPosOfStringEntry - stringsEntrySize);
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();
246 break;
247
248 default:
249 break;
250 }
251 return stringsEntrySize;
252 }
253
254 @Override
255 public long getStartTime() {
256 return start;
257 }
258
259 @Override
260 public long getEndTime() {
261 return end;
262 }
263
264 @Override
265 public long getViewerEndTime() {
266 return end + 1;
267 }
268
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
295 *
296 * @return
297 */
298 int getIntervalSize() {
299 return stringsEntrySize + HTNode.getDataEntrySize();
300 }
301
302 private int computeStringsEntrySize() {
303 switch(sv.getType()) {
304 case NULL:
305 case INTEGER:
306 /* Those don't use the strings section at all */
307 return 0;
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();
323 }
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 }
340
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 }
355
356 @Override
357 public String toString() {
358 /* Only for debug, should not be externalized */
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();
373 }
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;
387 case LONG:
388 return TYPE_LONG;
389 default:
390 /* Should not happen if the switch is fully covered */
391 throw new RuntimeException();
392 }
393 }
394 }
This page took 0.043878 seconds and 5 git commands to generate.