44eada2b9cc8c2b76d099b91d88a03577f500335
1 /*******************************************************************************
2 * Copyright (c) 2012, 2015 Ericsson, École Polytechnique de Montréal
3 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
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
11 * Alexandre Montplaisir - Initial API and implementation
12 * Florian Wininger - Allow to change the size of a interval
13 * Patrick Tasse - Add message to exceptions
14 *******************************************************************************/
16 package org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
;
18 import java
.io
.IOException
;
19 import java
.nio
.ByteBuffer
;
21 import org
.eclipse
.jdt
.annotation
.NonNull
;
22 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
23 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
24 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
25 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
28 * The interval component, which will be contained in a node of the History
31 * @author Alexandre Montplaisir
33 public final class HTInterval
implements ITmfStateInterval
, Comparable
<HTInterval
> {
35 private static final String errMsg
= "Invalid interval data. Maybe your file is corrupt?"; //$NON-NLS-1$
37 /* 'Byte' equivalent for state values types */
38 private static final byte TYPE_NULL
= -1;
39 private static final byte TYPE_INTEGER
= 0;
40 private static final byte TYPE_STRING
= 1;
41 private static final byte TYPE_LONG
= 2;
42 private static final byte TYPE_DOUBLE
= 3;
43 private static final byte TYPE_CUSTOM
= 20;
45 private final long start
;
46 private final long end
;
47 private final int attribute
;
48 private final @NonNull TmfStateValue sv
;
50 /** Number of bytes used by this interval when it is written to disk */
51 private final int fSizeOnDisk
;
54 * Standard constructor
56 * @param intervalStart
57 * Start time of the interval
59 * End time of the interval
61 * Attribute (quark) to which the state represented by this
64 * State value represented by this interval
65 * @throws TimeRangeException
66 * If the start time or end time are invalid
68 public HTInterval(long intervalStart
, long intervalEnd
, int attribute
,
69 @NonNull TmfStateValue value
) throws TimeRangeException
{
70 if (intervalStart
> intervalEnd
) {
71 throw new TimeRangeException("Start:" + intervalStart
+ ", End:" + intervalEnd
); //$NON-NLS-1$ //$NON-NLS-2$
74 this.start
= intervalStart
;
75 this.end
= intervalEnd
;
76 this.attribute
= attribute
;
78 this.fSizeOnDisk
= computeSizeOnDisk(sv
);
82 * Compute how much space (in bytes) an interval will take in its serialized
83 * form on disk. This is dependent on its state value.
85 private static int computeSizeOnDisk(ITmfStateValue sv
) {
87 * Minimum size is 2x long (start and end), 1x int (attribute) and 1x
90 int minSize
= Long
.BYTES
+ Long
.BYTES
+ Integer
.BYTES
+ Byte
.BYTES
;
92 switch (sv
.getType()) {
96 return (minSize
+ Integer
.BYTES
);
98 return (minSize
+ Long
.BYTES
);
100 return (minSize
+ Double
.BYTES
);
103 * String's length + 2 (1 byte for size, 1 byte for \0 at the end
105 return (minSize
+ sv
.unboxStr().getBytes().length
+ 2);
109 * It's very important that we know how to write the state value in
112 throw new IllegalStateException();
117 * "Faster" constructor for inner use only. When we build an interval when
118 * reading it from disk (with {@link #readFrom}), we already know the size
119 * of the strings entry, so there is no need to call
120 * {@link #computeStringsEntrySize()} and do an extra copy.
122 private HTInterval(long intervalStart
, long intervalEnd
, int attribute
,
123 @NonNull TmfStateValue value
, int size
) throws TimeRangeException
{
124 if (intervalStart
> intervalEnd
) {
125 throw new TimeRangeException("Start:" + intervalStart
+ ", End:" + intervalEnd
); //$NON-NLS-1$ //$NON-NLS-2$
128 this.start
= intervalStart
;
129 this.end
= intervalEnd
;
130 this.attribute
= attribute
;
132 this.fSizeOnDisk
= size
;
136 * Reader factory method. Builds the interval using an already-allocated
137 * ByteBuffer, which normally comes from a NIO FileChannel.
139 * The interval is just a start, end, attribute and value, this is the
140 * layout of the HTInterval on disk
142 * <li>start (8 bytes)</li>
143 * <li>end (8 bytes)</li>
144 * <li>attribute (4 bytes)</li>
145 * <li>sv type (1 byte)</li>
146 * <li>sv ( 0 bytes for null, 4 for int , 8 for long and double, and the
147 * length of the string +2 for strings (it's variable))</li>
151 * The ByteBuffer from which to read the information
152 * @return The interval object
153 * @throws IOException
154 * If there was an error reading from the buffer
156 public static final HTInterval
readFrom(ByteBuffer buffer
) throws IOException
{
158 long intervalStart
, intervalEnd
;
164 int posStart
= buffer
.position();
165 /* Read the Data Section entry */
166 intervalStart
= buffer
.getLong();
167 intervalEnd
= buffer
.getLong();
168 attribute
= buffer
.getInt();
170 /* Read the 'type' of the value, then react accordingly */
171 valueType
= buffer
.get();
175 value
= TmfStateValue
.nullValue();
179 value
= TmfStateValue
.newValueInt(buffer
.getInt());
183 /* the first byte = the size to read */
184 int valueSize
= buffer
.get();
186 array
= new byte[valueSize
];
188 value
= TmfStateValue
.newValueString(new String(array
));
190 /* Confirm the 0'ed byte at the end */
191 byte res
= buffer
.get();
193 throw new IOException(errMsg
);
198 /* Go read the matching entry in the Strings section of the block */
199 value
= TmfStateValue
.newValueLong(buffer
.getLong());
203 /* Go read the matching entry in the Strings section of the block */
204 value
= TmfStateValue
.newValueDouble(buffer
.getDouble());
209 /* Unknown data, better to not make anything up... */
210 throw new IOException(errMsg
);
214 interval
= new HTInterval(intervalStart
, intervalEnd
, attribute
, value
, buffer
.position() - posStart
);
215 } catch (TimeRangeException e
) {
216 throw new IOException(errMsg
);
222 * Antagonist of the previous constructor, write the Data entry
223 * corresponding to this interval in a ByteBuffer (mapped to a block in the
224 * history-file, hopefully)
226 * The interval is just a start, end, attribute and value, this is the
227 * layout of the HTInterval on disk
229 * <li>start (8 bytes)</li>
230 * <li>end (8 bytes)</li>
231 * <li>attribute (4 bytes)</li>
232 * <li>sv type (1 byte)</li>
233 * <li>sv ( 0 bytes for null, 4 for int , 8 for long and double, and the
234 * length of the string +2 for strings (it's variable))</li>
238 * The already-allocated ByteBuffer corresponding to a SHT Node
240 public void writeInterval(ByteBuffer buffer
) {
241 final byte byteFromType
= getByteFromType(sv
.getType());
243 buffer
.putLong(start
);
245 buffer
.putInt(attribute
);
246 buffer
.put(byteFromType
);
248 switch (byteFromType
) {
252 buffer
.putInt(sv
.unboxInt());
256 String string
= sv
.unboxStr();
257 byte[] strArray
= string
.getBytes();
260 * Write the Strings entry (1st byte = size, then the bytes, then
261 * the 0). We have checked the string length at the constructor.
263 buffer
.put((byte) strArray
.length
);
264 buffer
.put(strArray
);
265 buffer
.put((byte) 0);
269 buffer
.putLong(sv
.unboxLong());
273 buffer
.putDouble(sv
.unboxDouble());
282 public long getStartTime() {
287 public long getEndTime() {
292 public int getAttribute() {
297 public ITmfStateValue
getStateValue() {
302 public boolean intersects(long timestamp
) {
303 if (start
<= timestamp
) {
304 if (end
>= timestamp
) {
312 * Total serialized size of this interval
314 * @return The interval size
316 public int getSizeOnDisk() {
321 * Compare the END TIMES of different intervals. This is used to sort the
322 * intervals when we close down a node.
325 public int compareTo(HTInterval other
) {
326 if (this.end
< other
.end
) {
328 } else if (this.end
> other
.end
) {
336 public boolean equals(Object other
) {
337 if (other
instanceof HTInterval
&&
338 this.compareTo((HTInterval
) other
) == 0) {
345 public int hashCode() {
346 return super.hashCode();
350 public String
toString() {
351 /* Only for debug, should not be externalized */
352 StringBuilder sb
= new StringBuilder();
355 sb
.append(", "); //$NON-NLS-1$
359 sb
.append(", attribute = "); //$NON-NLS-1$
360 sb
.append(attribute
);
362 sb
.append(", value = "); //$NON-NLS-1$
363 sb
.append(sv
.toString());
365 return sb
.toString();
369 * Here we determine how state values "types" are written in the 8-bit field
370 * that indicates the value type in the file.
372 private static byte getByteFromType(ITmfStateValue
.Type type
) {
387 /* Should not happen if the switch is fully covered */
388 throw new IllegalStateException();
This page took 0.039618 seconds and 4 git commands to generate.