Merge Generic State System core part
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / statesystem / backend / historytree / HTInterval.java
1 /*******************************************************************************
2 * Copyright (c) 2012 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.tmf.core.statesystem.backend.historytree;
14
15 import java.io.IOException;
16 import java.nio.ByteBuffer;
17
18 import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
19 import org.eclipse.linuxtools.tmf.core.statesystem.TimeRangeException;
20 import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
21 import org.eclipse.linuxtools.tmf.core.statevalue.StateValueTypeException;
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 final long start;
34 private final long end;
35 private final int attribute;
36 private final TmfStateValue sv;
37
38 /*
39 * Size of the strings section entry used by this interval (= 0 if not used)
40 */
41 private final int stringsEntrySize;
42
43 /**
44 * Standard constructor
45 *
46 * @param intervalStart
47 * @param intervalEnd
48 * @param attribute
49 * @param value
50 * @throws TimeRangeException
51 */
52 HTInterval(long intervalStart, long intervalEnd, int attribute,
53 TmfStateValue value) throws TimeRangeException {
54 if (intervalStart > intervalEnd) {
55 throw new TimeRangeException();
56 }
57
58 this.start = intervalStart;
59 this.end = intervalEnd;
60 this.attribute = attribute;
61 this.sv = value;
62 this.stringsEntrySize = computeStringsEntrySize();
63 }
64
65 /**
66 * Reader constructor. Builds the interval using an already-allocated
67 * ByteBuffer, which normally comes from a NIO FileChannel.
68 *
69 * @param buffer
70 * The ByteBuffer from which to read the information
71 * @throws IOException
72 */
73 final static HTInterval readFrom(ByteBuffer buffer) throws IOException {
74 HTInterval interval;
75 long intervalStart, intervalEnd;
76 int attribute;
77 TmfStateValue value;
78 int valueOrOffset, valueSize, res;
79 byte valueType;
80 byte array[];
81
82 /* Read the Data Section entry */
83 intervalStart = buffer.getLong();
84 intervalEnd = buffer.getLong();
85 attribute = buffer.getInt();
86
87 /* Read the 'type' of the value, then react accordingly */
88 valueType = buffer.get();
89 if (valueType <= 0) {
90 /* the type of ValueOrOffset is 'value' */
91 valueOrOffset = buffer.getInt();
92 if (valueOrOffset == -1) {
93 /* Null value */
94 value = TmfStateValue.nullValue();
95 } else {
96 /* Normal integer value */
97 value = TmfStateValue.newValueInt(valueOrOffset);
98 }
99
100 } else { // valueType > 0
101 /* the type is 'offset' */
102 valueOrOffset = buffer.getInt();
103
104 /*
105 * Go read the corresponding entry in the Strings section of the
106 * block
107 */
108 buffer.mark();
109 buffer.position(valueOrOffset);
110
111 /* the first byte = the size to read */
112 valueSize = buffer.get();
113
114 /*
115 * Careful though, 'valueSize' is the total size of the entry,
116 * including the 'size' byte at the start and end (0'ed) byte at the
117 * end. Here we want 'array' to only contain the real payload of the
118 * value.
119 */
120 array = new byte[valueSize - 2];
121 buffer.get(array);
122 value = TmfStateValue.newValueString(new String(array));
123
124 /* Confirm the 0'ed byte at the end */
125 res = buffer.get();
126 if (res != 0) {
127 throw new IOException(
128 "Invalid interval data. Maybe your file is corrupt?"); //$NON-NLS-1$
129 }
130
131 /*
132 * Restore the file pointer's position (so we can read the next
133 * interval)
134 */
135 buffer.reset();
136 }
137
138 try {
139 interval = new HTInterval(intervalStart, intervalEnd, attribute,
140 value);
141 } catch (TimeRangeException e) {
142 throw new IOException(
143 "Invalid interval data. Maybe your file is corrupt?"); //$NON-NLS-1$
144 }
145 return interval;
146 }
147
148 /**
149 * Antagonist of the previous constructor, write the Data entry
150 * corresponding to this interval in a ByteBuffer (mapped to a block in the
151 * history-file, hopefully)
152 *
153 * @param buffer
154 * The already-allocated ByteBuffer corresponding to a SHT Node
155 * @param endPosOfStringEntry
156 * The initial (before calling this function for this interval)
157 * position of the Strings Entry for this node. This will change
158 * from one call to the other if we're writing String
159 * StateValues.
160 * @return The size of the Strings Entry that was written, if any.
161 */
162 int writeInterval(ByteBuffer buffer, int endPosOfStringEntry) {
163 int sizeOfStringEntry;
164 byte[] byteArrayToWrite;
165
166 buffer.putLong(start);
167 buffer.putLong(end);
168 buffer.putInt(attribute);
169 buffer.put(sv.getType());
170
171 byteArrayToWrite = sv.toByteArray();
172
173 if (byteArrayToWrite == null) {
174 /* We write the 'valueOffset' field as a straight value */
175 if (sv.isNull()) {
176 buffer.putInt(0);
177 } else {
178 try {
179 buffer.putInt(sv.unboxInt());
180 } catch (StateValueTypeException e) {
181 /*
182 * This should not happen, since the value told us it was of
183 * type Integer (corrupted value?)
184 */
185 e.printStackTrace();
186 }
187 }
188 return 0; /* we didn't use a Strings section entry */
189
190 }
191 /*
192 * Size to write (+2 = +1 for size at the start, +1 for the 0 at the
193 * end)
194 */
195 sizeOfStringEntry = byteArrayToWrite.length + 2;
196
197 /* we use the valueOffset as an offset. */
198 buffer.putInt(endPosOfStringEntry - sizeOfStringEntry);
199 buffer.mark();
200 buffer.position(endPosOfStringEntry - sizeOfStringEntry);
201
202 /*
203 * write the Strings entry (1st byte = size, then the bytes, then
204 * the 0)
205 */
206 buffer.put((byte) sizeOfStringEntry);
207 buffer.put(byteArrayToWrite);
208 buffer.put((byte) 0);
209 assert (buffer.position() == endPosOfStringEntry);
210 buffer.reset();
211 return sizeOfStringEntry;
212 }
213
214 @Override
215 public long getStartTime() {
216 return start;
217 }
218
219 @Override
220 public long getEndTime() {
221 return end;
222 }
223
224 @Override
225 public int getAttribute() {
226 return attribute;
227 }
228
229 @Override
230 public ITmfStateValue getStateValue() {
231 return sv;
232 }
233
234 @Override
235 public boolean intersects(long timestamp) {
236 if (start <= timestamp) {
237 if (end >= timestamp) {
238 return true;
239 }
240 }
241 return false;
242 }
243
244 int getStringsEntrySize() {
245 return stringsEntrySize;
246 }
247
248 /**
249 * Total serialized size of this interval
250 *
251 * @return
252 */
253 int getIntervalSize() {
254 return stringsEntrySize + HTNode.getDataEntrySize();
255 }
256
257 private int computeStringsEntrySize() {
258 if (sv.toByteArray() == null) {
259 return 0;
260 }
261 return sv.toByteArray().length + 2;
262 /* (+1 for the first byte indicating the size, +1 for the 0'ed byte) */
263 }
264
265 /**
266 * Compare the END TIMES of different intervals. This is used to sort the
267 * intervals when we close down a node.
268 */
269 @Override
270 public int compareTo(HTInterval other) {
271 if (this.end < other.end) {
272 return -1;
273 } else if (this.end > other.end) {
274 return 1;
275 } else {
276 return 0;
277 }
278 }
279 }
This page took 0.043376 seconds and 5 git commands to generate.