ss: no longer have a strings section in the HTNodes
[deliverable/tracecompass.git] / statesystem / org.eclipse.tracecompass.statesystem.core / src / org / eclipse / tracecompass / internal / statesystem / core / backend / historytree / HTInterval.java
CommitLineData
a52fde77 1/*******************************************************************************
e13bd4cd 2 * Copyright (c) 2012, 2015 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
e13bd4cd 13 * Patrick Tasse - Add message to exceptions
a52fde77
AM
14 *******************************************************************************/
15
e894a508 16package org.eclipse.tracecompass.internal.statesystem.core.backend.historytree;
a52fde77
AM
17
18import java.io.IOException;
19import java.nio.ByteBuffer;
20
aa353506 21import org.eclipse.jdt.annotation.NonNull;
e894a508
AM
22import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
23import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
24import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
25import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
a52fde77
AM
26
27/**
28 * The interval component, which will be contained in a node of the History
29 * Tree.
98107b3f 30 *
8d47cc34 31 * @author Alexandre Montplaisir
a52fde77 32 */
8d47cc34 33public final class HTInterval implements ITmfStateInterval, Comparable<HTInterval> {
a52fde77 34
b67a2540
AM
35 private static final String errMsg = "Invalid interval data. Maybe your file is corrupt?"; //$NON-NLS-1$
36
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;
1cbf1a19 41 private static final byte TYPE_LONG = 2;
a3c22e8e 42 private static final byte TYPE_DOUBLE = 3;
b67a2540 43
a52fde77
AM
44 private final long start;
45 private final long end;
46 private final int attribute;
aa353506 47 private final @NonNull TmfStateValue sv;
a52fde77 48
59d30d83
MK
49 /** Number of bytes used by this interval when it is written to disk */
50 private final int fSizeOnDisk;
a52fde77
AM
51
52 /**
53 * Standard constructor
98107b3f 54 *
a52fde77 55 * @param intervalStart
8d47cc34 56 * Start time of the interval
a52fde77 57 * @param intervalEnd
8d47cc34 58 * End time of the interval
a52fde77 59 * @param attribute
8d47cc34
AM
60 * Attribute (quark) to which the state represented by this
61 * interval belongs
a52fde77 62 * @param value
8d47cc34 63 * State value represented by this interval
a52fde77 64 * @throws TimeRangeException
8d47cc34 65 * If the start time or end time are invalid
a52fde77 66 */
8d47cc34 67 public HTInterval(long intervalStart, long intervalEnd, int attribute,
aa353506 68 @NonNull TmfStateValue value) throws TimeRangeException {
a52fde77 69 if (intervalStart > intervalEnd) {
e13bd4cd 70 throw new TimeRangeException("Start:" + intervalStart + ", End:" + intervalEnd); //$NON-NLS-1$ //$NON-NLS-2$
a52fde77
AM
71 }
72
73 this.start = intervalStart;
74 this.end = intervalEnd;
75 this.attribute = attribute;
76 this.sv = value;
59d30d83
MK
77 this.fSizeOnDisk = computeSizeOnDisk(sv);
78 }
79
80 /**
81 * Compute how much space (in bytes) an interval will take in its serialized
82 * form on disk. This is dependent on its state value.
83 */
84 private static int computeSizeOnDisk(ITmfStateValue sv) {
85 /*
86 * Minimum size is 2x long (start and end), 1x int (attribute) and 1x
87 * byte (value type).
88 */
89 int minSize = Long.BYTES + Long.BYTES + Integer.BYTES + Byte.BYTES;
90
91 switch (sv.getType()) {
92 case NULL:
93 return minSize;
94 case INTEGER:
95 return (minSize + Integer.BYTES);
96 case LONG:
97 return (minSize + Long.BYTES);
98 case DOUBLE:
99 return (minSize + Double.BYTES);
100 case STRING:
101 /*
102 * String's length + 2 (1 byte for size, 1 byte for \0 at the end
103 */
104 return (minSize + sv.unboxStr().getBytes().length + 2);
105 default:
106 /*
107 * It's very important that we know how to write the state value in
108 * the file!!
109 */
110 throw new IllegalStateException();
111 }
a52fde77
AM
112 }
113
b4603a60
AM
114 /**
115 * "Faster" constructor for inner use only. When we build an interval when
116 * reading it from disk (with {@link #readFrom}), we already know the size
117 * of the strings entry, so there is no need to call
118 * {@link #computeStringsEntrySize()} and do an extra copy.
b4603a60
AM
119 */
120 private HTInterval(long intervalStart, long intervalEnd, int attribute,
aa353506 121 @NonNull TmfStateValue value, int size) throws TimeRangeException {
b4603a60 122 if (intervalStart > intervalEnd) {
e13bd4cd 123 throw new TimeRangeException("Start:" + intervalStart + ", End:" + intervalEnd); //$NON-NLS-1$ //$NON-NLS-2$
b4603a60
AM
124 }
125
126 this.start = intervalStart;
127 this.end = intervalEnd;
128 this.attribute = attribute;
129 this.sv = value;
59d30d83 130 this.fSizeOnDisk = size;
b4603a60
AM
131 }
132
a52fde77 133 /**
8d47cc34 134 * Reader factory method. Builds the interval using an already-allocated
a52fde77 135 * ByteBuffer, which normally comes from a NIO FileChannel.
98107b3f 136 *
59d30d83
MK
137 * The interval is just a start, end, attribute and value, this is the
138 * layout of the HTInterval on disk
139 * <ul>
140 * <li>start (8 bytes)</li>
141 * <li>end (8 bytes)</li>
142 * <li>attribute (4 bytes)</li>
143 * <li>sv type (1 byte)</li>
144 * <li>sv ( 0 bytes for null, 4 for int , 8 for long and double, and the
145 * length of the string +2 for strings (it's variable))</li>
146 * </ul>
147 *
a52fde77
AM
148 * @param buffer
149 * The ByteBuffer from which to read the information
8d47cc34 150 * @return The interval object
a52fde77 151 * @throws IOException
8d47cc34 152 * If there was an error reading from the buffer
a52fde77 153 */
8d47cc34 154 public static final HTInterval readFrom(ByteBuffer buffer) throws IOException {
a52fde77
AM
155 HTInterval interval;
156 long intervalStart, intervalEnd;
157 int attribute;
158 TmfStateValue value;
a52fde77
AM
159 byte valueType;
160 byte array[];
161
59d30d83 162 int posStart = buffer.position();
a52fde77
AM
163 /* Read the Data Section entry */
164 intervalStart = buffer.getLong();
165 intervalEnd = buffer.getLong();
166 attribute = buffer.getInt();
167
168 /* Read the 'type' of the value, then react accordingly */
169 valueType = buffer.get();
b67a2540 170 switch (valueType) {
a52fde77 171
b67a2540
AM
172 case TYPE_NULL:
173 value = TmfStateValue.nullValue();
174 break;
a52fde77 175
b67a2540 176 case TYPE_INTEGER:
59d30d83 177 value = TmfStateValue.newValueInt(buffer.getInt());
b67a2540
AM
178 break;
179
180 case TYPE_STRING:
a52fde77 181 /* the first byte = the size to read */
59d30d83 182 int valueSize = buffer.get();
a52fde77 183
59d30d83 184 array = new byte[valueSize];
a52fde77
AM
185 buffer.get(array);
186 value = TmfStateValue.newValueString(new String(array));
187
188 /* Confirm the 0'ed byte at the end */
59d30d83 189 byte res = buffer.get();
a52fde77 190 if (res != 0) {
b67a2540 191 throw new IOException(errMsg);
a52fde77 192 }
1cbf1a19
FR
193 break;
194
195 case TYPE_LONG:
196 /* Go read the matching entry in the Strings section of the block */
1cbf1a19 197 value = TmfStateValue.newValueLong(buffer.getLong());
b67a2540 198 break;
a3c22e8e
AM
199
200 case TYPE_DOUBLE:
201 /* Go read the matching entry in the Strings section of the block */
a3c22e8e 202 value = TmfStateValue.newValueDouble(buffer.getDouble());
a3c22e8e
AM
203 break;
204
b67a2540
AM
205 default:
206 /* Unknown data, better to not make anything up... */
207 throw new IOException(errMsg);
a52fde77
AM
208 }
209
210 try {
59d30d83 211 interval = new HTInterval(intervalStart, intervalEnd, attribute, value, buffer.position() - posStart);
a52fde77 212 } catch (TimeRangeException e) {
b67a2540 213 throw new IOException(errMsg);
a52fde77
AM
214 }
215 return interval;
216 }
217
218 /**
219 * Antagonist of the previous constructor, write the Data entry
220 * corresponding to this interval in a ByteBuffer (mapped to a block in the
221 * history-file, hopefully)
98107b3f 222 *
59d30d83
MK
223 * The interval is just a start, end, attribute and value, this is the
224 * layout of the HTInterval on disk
225 * <ul>
226 * <li>start (8 bytes)</li>
227 * <li>end (8 bytes)</li>
228 * <li>attribute (4 bytes)</li>
229 * <li>sv type (1 byte)</li>
230 * <li>sv ( 0 bytes for null, 4 for int , 8 for long and double, and the
231 * length of the string +2 for strings (it's variable))</li>
232 * </ul>
233 *
a52fde77
AM
234 * @param buffer
235 * The already-allocated ByteBuffer corresponding to a SHT Node
a52fde77 236 */
59d30d83
MK
237 public void writeInterval(ByteBuffer buffer) {
238 final byte byteFromType = getByteFromType(sv.getType());
239
a52fde77
AM
240 buffer.putLong(start);
241 buffer.putLong(end);
242 buffer.putInt(attribute);
59d30d83 243 buffer.put(byteFromType);
a52fde77 244
59d30d83 245 switch (byteFromType) {
1cbf1a19 246 case TYPE_NULL:
59d30d83 247 break;
1cbf1a19 248 case TYPE_INTEGER:
59d30d83 249 buffer.putInt(sv.unboxInt());
9177eb74 250 break;
a52fde77 251
1cbf1a19 252 case TYPE_STRING:
59d30d83
MK
253 String string = sv.unboxStr();
254 byte[] strArray = string.getBytes();
1cbf1a19
FR
255
256 /*
59d30d83
MK
257 * Write the Strings entry (1st byte = size, then the bytes, then
258 * the 0). We have checked the string length at the constructor.
1cbf1a19 259 */
59d30d83
MK
260 buffer.put((byte) strArray.length);
261 buffer.put(strArray);
1cbf1a19 262 buffer.put((byte) 0);
9177eb74 263 break;
1cbf1a19
FR
264
265 case TYPE_LONG:
59d30d83 266 buffer.putLong(sv.unboxLong());
9177eb74 267 break;
1cbf1a19 268
a3c22e8e 269 case TYPE_DOUBLE:
59d30d83 270 buffer.putDouble(sv.unboxDouble());
a3c22e8e
AM
271 break;
272
1cbf1a19 273 default:
9177eb74 274 break;
a52fde77 275 }
a52fde77
AM
276 }
277
278 @Override
279 public long getStartTime() {
280 return start;
281 }
282
283 @Override
284 public long getEndTime() {
285 return end;
286 }
287
288 @Override
289 public int getAttribute() {
290 return attribute;
291 }
292
293 @Override
294 public ITmfStateValue getStateValue() {
295 return sv;
296 }
297
298 @Override
299 public boolean intersects(long timestamp) {
300 if (start <= timestamp) {
301 if (end >= timestamp) {
302 return true;
303 }
304 }
305 return false;
306 }
307
a52fde77
AM
308 /**
309 * Total serialized size of this interval
98107b3f 310 *
8d47cc34 311 * @return The interval size
a52fde77 312 */
59d30d83
MK
313 public int getSizeOnDisk() {
314 return fSizeOnDisk;
a52fde77
AM
315 }
316
317 /**
318 * Compare the END TIMES of different intervals. This is used to sort the
319 * intervals when we close down a node.
320 */
321 @Override
322 public int compareTo(HTInterval other) {
323 if (this.end < other.end) {
324 return -1;
325 } else if (this.end > other.end) {
326 return 1;
327 } else {
328 return 0;
329 }
330 }
1b558482 331
ab604305
AM
332 @Override
333 public boolean equals(Object other) {
cb42195c
AM
334 if (other instanceof HTInterval &&
335 this.compareTo((HTInterval) other) == 0) {
336 return true;
ab604305
AM
337 }
338 return false;
339 }
340
341 @Override
342 public int hashCode() {
343 return super.hashCode();
344 }
1b558482
AM
345
346 @Override
347 public String toString() {
348 /* Only for debug, should not be externalized */
98107b3f
AM
349 StringBuilder sb = new StringBuilder();
350 sb.append('[');
351 sb.append(start);
352 sb.append(", "); //$NON-NLS-1$
353 sb.append(end);
354 sb.append(']');
355
356 sb.append(", attribute = "); //$NON-NLS-1$
357 sb.append(attribute);
358
359 sb.append(", value = "); //$NON-NLS-1$
360 sb.append(sv.toString());
361
362 return sb.toString();
1b558482 363 }
b67a2540
AM
364
365 /**
59d30d83
MK
366 * Here we determine how state values "types" are written in the 8-bit field
367 * that indicates the value type in the file.
b67a2540
AM
368 */
369 private static byte getByteFromType(ITmfStateValue.Type type) {
59d30d83 370 switch (type) {
b67a2540
AM
371 case NULL:
372 return TYPE_NULL;
373 case INTEGER:
374 return TYPE_INTEGER;
375 case STRING:
376 return TYPE_STRING;
1cbf1a19
FR
377 case LONG:
378 return TYPE_LONG;
a3c22e8e
AM
379 case DOUBLE:
380 return TYPE_DOUBLE;
b67a2540
AM
381 default:
382 /* Should not happen if the switch is fully covered */
cb42195c 383 throw new IllegalStateException();
b67a2540
AM
384 }
385 }
a52fde77 386}
This page took 0.097532 seconds and 5 git commands to generate.