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>
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
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.internal
.tmf
.core
.statesystem
.backends
.historytree
;
15 import java
.io
.IOException
;
16 import java
.nio
.ByteBuffer
;
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
;
25 * The interval component, which will be contained in a node of the History
31 final class HTInterval
implements ITmfStateInterval
, Comparable
<HTInterval
> {
33 private static final String errMsg
= "Invalid interval data. Maybe your file is corrupt?"; //$NON-NLS-1$
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;
41 private final long start
;
42 private final long end
;
43 private final int attribute
;
44 private final TmfStateValue sv
;
47 * Size of the strings section entry used by this interval (= 0 if not used)
49 private final int stringsEntrySize
;
52 * Standard constructor
54 * @param intervalStart
58 * @throws TimeRangeException
60 HTInterval(long intervalStart
, long intervalEnd
, int attribute
,
61 TmfStateValue value
) throws TimeRangeException
{
62 if (intervalStart
> intervalEnd
) {
63 throw new TimeRangeException();
66 this.start
= intervalStart
;
67 this.end
= intervalEnd
;
68 this.attribute
= attribute
;
70 this.stringsEntrySize
= computeStringsEntrySize();
74 * Reader constructor. Builds the interval using an already-allocated
75 * ByteBuffer, which normally comes from a NIO FileChannel.
78 * The ByteBuffer from which to read the information
81 final static HTInterval
readFrom(ByteBuffer buffer
) throws IOException
{
83 long intervalStart
, intervalEnd
;
86 int valueOrOffset
, valueSize
, res
;
90 /* Read the Data Section entry */
91 intervalStart
= buffer
.getLong();
92 intervalEnd
= buffer
.getLong();
93 attribute
= buffer
.getInt();
95 /* Read the 'type' of the value, then react accordingly */
96 valueType
= buffer
.get();
97 valueOrOffset
= buffer
.getInt();
101 value
= TmfStateValue
.nullValue();
105 /* "ValueOrOffset" is the straight value */
106 value
= TmfStateValue
.newValueInt(valueOrOffset
);
110 /* Go read the matching entry in the Strings section of the block */
112 buffer
.position(valueOrOffset
);
114 /* the first byte = the size to read */
115 valueSize
= buffer
.get();
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
123 array
= new byte[valueSize
- 2];
125 value
= TmfStateValue
.newValueString(new String(array
));
127 /* Confirm the 0'ed byte at the end */
130 throw new IOException(errMsg
);
134 * Restore the file pointer's position (so we can read the next
141 /* Go read the matching entry in the Strings section of the block */
143 buffer
.position(valueOrOffset
);
144 value
= TmfStateValue
.newValueLong(buffer
.getLong());
147 * Restore the file pointer's position (so we can read the next
153 /* Unknown data, better to not make anything up... */
154 throw new IOException(errMsg
);
158 interval
= new HTInterval(intervalStart
, intervalEnd
, attribute
, value
);
159 } catch (TimeRangeException e
) {
160 throw new IOException(errMsg
);
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)
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
177 * @return The size of the Strings Entry that was written, if any.
179 int writeInterval(ByteBuffer buffer
, int endPosOfStringEntry
) {
180 buffer
.putLong(start
);
182 buffer
.putInt(attribute
);
183 buffer
.put(getByteFromType(sv
.getType()));
185 switch (getByteFromType(sv
.getType())) {
189 /* We write the 'valueOffset' field as a straight value. In the case
190 * of a null value, it will be unboxed as -1 */
192 buffer
.putInt(sv
.unboxInt());
193 } catch (StateValueTypeException e
) {
195 * This should not happen, since the value told us it was of
196 * type Null or Integer (corrupted value?)
203 byte[] byteArrayToWrite
;
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();
211 /* we use the valueOffset as an offset. */
212 buffer
.putInt(endPosOfStringEntry
- stringsEntrySize
);
214 buffer
.position(endPosOfStringEntry
- stringsEntrySize
);
217 * write the Strings entry (1st byte = size, then the bytes, then the 0)
219 buffer
.put((byte) stringsEntrySize
);
220 buffer
.put(byteArrayToWrite
);
221 buffer
.put((byte) 0);
222 assert (buffer
.position() == endPosOfStringEntry
);
227 /* we use the valueOffset as an offset. */
228 buffer
.putInt(endPosOfStringEntry
- stringsEntrySize
);
230 buffer
.position(endPosOfStringEntry
- stringsEntrySize
);
233 * write the Long in the Strings section
236 buffer
.putLong(sv
.unboxLong());
237 } catch (StateValueTypeException e
) {
239 * This should not happen, since the value told us it was of
240 * type Long (corrupted value?)
244 assert (buffer
.position() == endPosOfStringEntry
);
251 return stringsEntrySize
;
255 public long getStartTime() {
260 public long getEndTime() {
265 public long getViewerEndTime() {
270 public int getAttribute() {
275 public ITmfStateValue
getStateValue() {
280 public boolean intersects(long timestamp
) {
281 if (start
<= timestamp
) {
282 if (end
>= timestamp
) {
289 int getStringsEntrySize() {
290 return stringsEntrySize
;
294 * Total serialized size of this interval
298 int getIntervalSize() {
299 return stringsEntrySize
+ HTNode
.DATA_ENTRY_SIZE
;
302 private int computeStringsEntrySize() {
303 switch(sv
.getType()) {
306 /* Those don't use the strings section at all */
309 /* The value's bytes are written directly into the strings section */
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 IllegalStateException(e
);
320 /* It's very important that we know how to write the state value in
322 throw new IllegalStateException();
327 * Compare the END TIMES of different intervals. This is used to sort the
328 * intervals when we close down a node.
331 public int compareTo(HTInterval other
) {
332 if (this.end
< other
.end
) {
334 } else if (this.end
> other
.end
) {
342 public boolean equals(Object other
) {
343 if (other
instanceof HTInterval
&&
344 this.compareTo((HTInterval
) other
) == 0) {
351 public int hashCode() {
352 return super.hashCode();
356 public String
toString() {
357 /* Only for debug, should not be externalized */
358 StringBuilder sb
= new StringBuilder();
361 sb
.append(", "); //$NON-NLS-1$
365 sb
.append(", attribute = "); //$NON-NLS-1$
366 sb
.append(attribute
);
368 sb
.append(", value = "); //$NON-NLS-1$
369 sb
.append(sv
.toString());
371 return sb
.toString();
375 * Here we determine how state values "types" are written in the 8-bit
376 * field that indicates the value type in the file.
378 private static byte getByteFromType(ITmfStateValue
.Type type
) {
389 /* Should not happen if the switch is fully covered */
390 throw new IllegalStateException();