ss: Switch the statesystem to the datastore HT
[deliverable/tracecompass.git] / statesystem / org.eclipse.tracecompass.statesystem.core / src / org / eclipse / tracecompass / internal / statesystem / core / backend / historytree / StateSystemInterval.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2015 Ericsson, École Polytechnique de Montréal
3 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
4 *
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
9 *
10 * Contributors:
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 *******************************************************************************/
15
16 package org.eclipse.tracecompass.internal.statesystem.core.backend.historytree;
17
18 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
19
20 import java.nio.charset.Charset;
21 import java.util.Objects;
22
23 import org.eclipse.jdt.annotation.NonNull;
24 import org.eclipse.tracecompass.internal.provisional.datastore.core.interval.HTInterval;
25 import org.eclipse.tracecompass.internal.provisional.datastore.core.interval.IHTIntervalReader;
26 import org.eclipse.tracecompass.internal.provisional.datastore.core.serialization.ISafeByteBufferWriter;
27 import org.eclipse.tracecompass.internal.provisional.statesystem.core.statevalue.CustomStateValue;
28 import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
29 import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
30 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
31 import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
32
33 /**
34 * The interval component, which will be contained in a node of the History
35 * Tree.
36 *
37 * @author Alexandre Montplaisir
38 */
39 public final class StateSystemInterval extends HTInterval implements ITmfStateInterval {
40
41 private static final Charset CHARSET = Charset.forName("UTF-8"); //$NON-NLS-1$
42
43 private static final String errMsg = "Invalid interval data. Maybe your file is corrupt?"; //$NON-NLS-1$
44
45 /* 'Byte' equivalent for state values types */
46 private static final byte TYPE_NULL = -1;
47 private static final byte TYPE_INTEGER = 0;
48 private static final byte TYPE_STRING = 1;
49 private static final byte TYPE_LONG = 2;
50 private static final byte TYPE_DOUBLE = 3;
51 private static final byte TYPE_CUSTOM = 20;
52
53 private final int fAttribute;
54 private final @NonNull TmfStateValue fSv;
55
56 /** Number of bytes used by this interval when it is written to disk */
57 private final int fSizeOnDisk;
58
59 /**
60 * Standard constructor
61 *
62 * @param intervalStart
63 * Start time of the interval
64 * @param intervalEnd
65 * End time of the interval
66 * @param attribute
67 * Attribute (quark) to which the state represented by this
68 * interval belongs
69 * @param value
70 * State value represented by this interval
71 * @throws TimeRangeException
72 * If the start time or end time are invalid
73 */
74 public StateSystemInterval(long intervalStart, long intervalEnd, int attribute,
75 @NonNull TmfStateValue value) throws TimeRangeException {
76 super(intervalStart, intervalEnd);
77
78 fAttribute = attribute;
79 fSv = value;
80 fSizeOnDisk = computeSizeOnDisk(fSv);
81 }
82
83 /**
84 * Compute how much space (in bytes) an interval will take in its serialized
85 * form on disk. This is dependent on its state value.
86 */
87 private static int computeSizeOnDisk(ITmfStateValue sv) {
88 /*
89 * Minimum size is 2x long (start and end), 1x int (attribute) and 1x
90 * byte (value type).
91 */
92 int minSize = Long.BYTES + Long.BYTES + Integer.BYTES + Byte.BYTES;
93
94 switch (sv.getType()) {
95 case NULL:
96 return minSize;
97 case INTEGER:
98 return (minSize + Integer.BYTES);
99 case LONG:
100 return (minSize + Long.BYTES);
101 case DOUBLE:
102 return (minSize + Double.BYTES);
103 case STRING:
104 String str = sv.unboxStr();
105 int strLength = str.getBytes(CHARSET).length;
106
107 if (strLength > Short.MAX_VALUE) {
108 throw new IllegalArgumentException("String is too long to be stored in state system: " + str); //$NON-NLS-1$
109 }
110
111 /*
112 * String's length + 3 (2 bytes for size, 1 byte for \0 at the end)
113 */
114 return (minSize + strLength + 3);
115 case CUSTOM:
116 /* Length of serialized value (short) + state value */
117 return (minSize + Short.BYTES + ((CustomStateValue) sv).getSerializedSize());
118 default:
119 /*
120 * It's very important that we know how to write the state value in
121 * the file!!
122 */
123 throw new IllegalStateException();
124 }
125 }
126
127 /**
128 * Reader object for this interval type.
129 */
130 public static final @NonNull IHTIntervalReader<@NonNull StateSystemInterval> DESERIALISER = buffer -> {
131 TmfStateValue value;
132
133 /* Read the Data Section entry */
134 long intervalStart = buffer.getLong();
135 long intervalEnd = buffer.getLong();
136 int attribute = buffer.getInt();
137
138 /* Read the 'type' of the value, then react accordingly */
139 byte valueType = buffer.get();
140 switch (valueType) {
141
142 case TYPE_NULL:
143 value = TmfStateValue.nullValue();
144 break;
145
146 case TYPE_INTEGER:
147 value = TmfStateValue.newValueInt(buffer.getInt());
148 break;
149
150 case TYPE_STRING: {
151 /* the first short = the size to read */
152 int valueSize = buffer.getShort();
153
154 byte[] array = new byte[valueSize];
155 buffer.get(array);
156 value = TmfStateValue.newValueString(new String(array, CHARSET));
157
158 /* Confirm the 0'ed byte at the end */
159 byte res = buffer.get();
160 if (res != 0) {
161 throw new RuntimeException(errMsg);
162 }
163 break;
164 }
165
166 case TYPE_LONG:
167 /* Go read the matching entry in the Strings section of the block */
168 value = TmfStateValue.newValueLong(buffer.getLong());
169 break;
170
171 case TYPE_DOUBLE:
172 /* Go read the matching entry in the Strings section of the block */
173 value = TmfStateValue.newValueDouble(buffer.getDouble());
174 break;
175
176 case TYPE_CUSTOM: {
177 buffer.getShort();
178 // short valueSize = buffer.getShort();
179 // ISafeByteBufferReader safeBuffer =
180 // SafeByteBufferFactory.wrapReader(buffer, valueSize);
181 value = CustomStateValue.readSerializedValue(buffer);
182 break;
183 }
184 default:
185 /* Unknown data, better to not make anything up... */
186 throw new RuntimeException(errMsg);
187 }
188
189 try {
190 return new StateSystemInterval(intervalStart, intervalEnd, attribute, value);
191 } catch (TimeRangeException e) {
192 throw new RuntimeException(errMsg);
193 }
194 };
195
196 @Override
197 public void writeSegment(ISafeByteBufferWriter buffer) {
198 final byte byteFromType = getByteFromType(fSv.getType());
199
200 buffer.putLong(getStart());
201 buffer.putLong(getEnd());
202 buffer.putInt(fAttribute);
203 buffer.put(byteFromType);
204
205 switch (byteFromType) {
206 case TYPE_NULL:
207 break;
208 case TYPE_INTEGER:
209 buffer.putInt(fSv.unboxInt());
210 break;
211
212 case TYPE_STRING: {
213 String string = fSv.unboxStr();
214 byte[] strArray = string.getBytes(CHARSET);
215
216 /*
217 * Write the Strings entry (1st byte = size, then the bytes, then
218 * the 0). We have checked the string length at the constructor.
219 */
220 buffer.putShort((short) strArray.length);
221 buffer.put(strArray);
222 buffer.put((byte) 0);
223 break;
224 }
225
226 case TYPE_LONG:
227 buffer.putLong(fSv.unboxLong());
228 break;
229
230 case TYPE_DOUBLE:
231 buffer.putDouble(fSv.unboxDouble());
232 break;
233
234 case TYPE_CUSTOM: {
235 int size = ((CustomStateValue) fSv).getSerializedSize();
236 buffer.putShort((short) size);
237 // TODO: We send the full safe buffer to the custom value, its size
238 // should set to the necessary size only
239 ((CustomStateValue) fSv).serialize(buffer);
240 break;
241 }
242
243 default:
244 break;
245 }
246 }
247
248 // FIXME Remove these two duplicate methods
249
250 @Override
251 public long getStartTime() {
252 return getStart();
253 }
254
255 @Override
256 public long getEndTime() {
257 return getEnd();
258 }
259
260 @Override
261 public int getAttribute() {
262 return fAttribute;
263 }
264
265 @Override
266 public ITmfStateValue getStateValue() {
267 return fSv;
268 }
269
270 @Override
271 public boolean intersects(long timestamp) {
272 /*
273 * Need to explicitly re-define due to conflicting methods in
274 * super-interfaces.
275 */
276 return super.intersects(timestamp);
277 }
278
279 @Override
280 public int getSizeOnDisk() {
281 return fSizeOnDisk;
282 }
283
284 @Override
285 public int hashCode() {
286 return Objects.hash(super.hashCode(), fAttribute, fSv);
287 }
288
289 @Override
290 public boolean equals(Object obj) {
291 if (!super.equals(obj)) {
292 return false;
293 }
294
295 StateSystemInterval other = (StateSystemInterval) checkNotNull(obj);
296 return (fAttribute == other.fAttribute
297 && fSv.equals(other.fSv));
298 }
299
300 @Override
301 public String toString() {
302 /* Only for debug, should not be externalized */
303 StringBuilder sb = new StringBuilder();
304 sb.append('[');
305 sb.append(getStart());
306 sb.append(", "); //$NON-NLS-1$
307 sb.append(getEnd());
308 sb.append(']');
309
310 sb.append(", attribute = "); //$NON-NLS-1$
311 sb.append(fAttribute);
312
313 sb.append(", value = "); //$NON-NLS-1$
314 sb.append(fSv.toString());
315
316 return sb.toString();
317 }
318
319 /**
320 * Here we determine how state values "types" are written in the 8-bit field
321 * that indicates the value type in the file.
322 */
323 private static byte getByteFromType(ITmfStateValue.Type type) {
324 switch (type) {
325 case NULL:
326 return TYPE_NULL;
327 case INTEGER:
328 return TYPE_INTEGER;
329 case STRING:
330 return TYPE_STRING;
331 case LONG:
332 return TYPE_LONG;
333 case DOUBLE:
334 return TYPE_DOUBLE;
335 case CUSTOM:
336 return TYPE_CUSTOM;
337 default:
338 /* Should not happen if the switch is fully covered */
339 throw new IllegalStateException();
340 }
341 }
342 }
This page took 0.070272 seconds and 5 git commands to generate.