~ubuntu-branches/ubuntu/utopic/eclipse-linuxtools/utopic

« back to all changes in this revision

Viewing changes to lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HTInterval.java

  • Committer: Package Import Robot
  • Author(s): Jakub Adam
  • Date: 2014-05-12 18:11:40 UTC
  • mfrom: (3.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20140512181140-w237r3vsah1tmybz
Tags: 2.2.1-1
* New upstream release.
* Refreshed d/patches.
* Removed eclipse-cdt-valgrind-remote package, all its functionality
  is now provided by eclipse-cdt-profiling-framework-remote.
* Added remove-license-feature.patch.
* Bump Standards-Version to 3.9.5.
* Enable eclipse-changelog package.
* Enable eclipse-rpm-editor package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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>
 
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.internal.tmf.core.statesystem.backends.historytree;
 
14
 
 
15
import java.io.IOException;
 
16
import java.nio.ByteBuffer;
 
17
 
 
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;
 
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 static final String errMsg = "Invalid interval data. Maybe your file is corrupt?"; //$NON-NLS-1$
 
34
 
 
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;
 
40
 
 
41
    /* String entry sizes of different state values */
 
42
    private static final int NO_ENTRY_SIZE = 0;
 
43
    private static final int LONG_ENTRY_SIZE = 8;
 
44
    // sizes of string values depend on the string itself
 
45
 
 
46
    private final long start;
 
47
    private final long end;
 
48
    private final int attribute;
 
49
    private final TmfStateValue sv;
 
50
 
 
51
    /*
 
52
     * Size of the strings section entry used by this interval (= 0 if not used)
 
53
     */
 
54
    private final int stringsEntrySize;
 
55
 
 
56
    /**
 
57
     * Standard constructor
 
58
     *
 
59
     * @param intervalStart
 
60
     * @param intervalEnd
 
61
     * @param attribute
 
62
     * @param value
 
63
     * @throws TimeRangeException
 
64
     */
 
65
    HTInterval(long intervalStart, long intervalEnd, int attribute,
 
66
            TmfStateValue value) throws TimeRangeException {
 
67
        if (intervalStart > intervalEnd) {
 
68
            throw new TimeRangeException();
 
69
        }
 
70
 
 
71
        this.start = intervalStart;
 
72
        this.end = intervalEnd;
 
73
        this.attribute = attribute;
 
74
        this.sv = value;
 
75
        this.stringsEntrySize = computeStringsEntrySize();
 
76
    }
 
77
 
 
78
    /**
 
79
     * "Faster" constructor for inner use only. When we build an interval when
 
80
     * reading it from disk (with {@link #readFrom}), we already know the size
 
81
     * of the strings entry, so there is no need to call
 
82
     * {@link #computeStringsEntrySize()} and do an extra copy.
 
83
     *
 
84
     * @param intervalStart
 
85
     * @param intervalEnd
 
86
     * @param attribute
 
87
     * @param value
 
88
     * @param size
 
89
     * @throws TimeRangeException
 
90
     */
 
91
    private HTInterval(long intervalStart, long intervalEnd, int attribute,
 
92
            TmfStateValue value, int size) throws TimeRangeException {
 
93
        if (intervalStart > intervalEnd) {
 
94
            throw new TimeRangeException();
 
95
        }
 
96
 
 
97
        this.start = intervalStart;
 
98
        this.end = intervalEnd;
 
99
        this.attribute = attribute;
 
100
        this.sv = value;
 
101
        this.stringsEntrySize = size;
 
102
    }
 
103
 
 
104
    /**
 
105
     * Reader constructor. Builds the interval using an already-allocated
 
106
     * ByteBuffer, which normally comes from a NIO FileChannel.
 
107
     *
 
108
     * @param buffer
 
109
     *            The ByteBuffer from which to read the information
 
110
     * @throws IOException
 
111
     */
 
112
    final static HTInterval readFrom(ByteBuffer buffer) throws IOException {
 
113
        HTInterval interval;
 
114
        long intervalStart, intervalEnd;
 
115
        int attribute;
 
116
        TmfStateValue value;
 
117
        int valueOrOffset, valueSize, res;
 
118
        byte valueType;
 
119
        byte array[];
 
120
 
 
121
        /* Read the Data Section entry */
 
122
        intervalStart = buffer.getLong();
 
123
        intervalEnd = buffer.getLong();
 
124
        attribute = buffer.getInt();
 
125
 
 
126
        /* Read the 'type' of the value, then react accordingly */
 
127
        valueType = buffer.get();
 
128
        valueOrOffset = buffer.getInt();
 
129
        switch (valueType) {
 
130
 
 
131
        case TYPE_NULL:
 
132
            value = TmfStateValue.nullValue();
 
133
            valueSize = NO_ENTRY_SIZE;
 
134
            break;
 
135
 
 
136
        case TYPE_INTEGER:
 
137
            /* "ValueOrOffset" is the straight value */
 
138
            value = TmfStateValue.newValueInt(valueOrOffset);
 
139
            valueSize = NO_ENTRY_SIZE;
 
140
            break;
 
141
 
 
142
        case TYPE_STRING:
 
143
            /* Go read the matching entry in the Strings section of the block */
 
144
            buffer.mark();
 
145
            buffer.position(valueOrOffset);
 
146
 
 
147
            /* the first byte = the size to read */
 
148
            valueSize = buffer.get();
 
149
 
 
150
            /*
 
151
             * Careful though, 'valueSize' is the total size of the entry,
 
152
             * including the 'size' byte at the start and end (0'ed) byte at the
 
153
             * end. Here we want 'array' to only contain the real payload of the
 
154
             * value.
 
155
             */
 
156
            array = new byte[valueSize - 2];
 
157
            buffer.get(array);
 
158
            value = TmfStateValue.newValueString(new String(array));
 
159
 
 
160
            /* Confirm the 0'ed byte at the end */
 
161
            res = buffer.get();
 
162
            if (res != 0) {
 
163
                throw new IOException(errMsg);
 
164
            }
 
165
 
 
166
            /*
 
167
             * Restore the file pointer's position (so we can read the next
 
168
             * interval)
 
169
             */
 
170
            buffer.reset();
 
171
            break;
 
172
 
 
173
        case TYPE_LONG:
 
174
            /* Go read the matching entry in the Strings section of the block */
 
175
            buffer.mark();
 
176
            buffer.position(valueOrOffset);
 
177
            value = TmfStateValue.newValueLong(buffer.getLong());
 
178
            valueSize = LONG_ENTRY_SIZE;
 
179
 
 
180
            /*
 
181
             * Restore the file pointer's position (so we can read the next
 
182
             * interval)
 
183
             */
 
184
            buffer.reset();
 
185
            break;
 
186
        default:
 
187
            /* Unknown data, better to not make anything up... */
 
188
            throw new IOException(errMsg);
 
189
        }
 
190
 
 
191
        try {
 
192
            interval = new HTInterval(intervalStart, intervalEnd, attribute, value, valueSize);
 
193
        } catch (TimeRangeException e) {
 
194
            throw new IOException(errMsg);
 
195
        }
 
196
        return interval;
 
197
    }
 
198
 
 
199
    /**
 
200
     * Antagonist of the previous constructor, write the Data entry
 
201
     * corresponding to this interval in a ByteBuffer (mapped to a block in the
 
202
     * history-file, hopefully)
 
203
     *
 
204
     * @param buffer
 
205
     *            The already-allocated ByteBuffer corresponding to a SHT Node
 
206
     * @param endPosOfStringEntry
 
207
     *            The initial (before calling this function for this interval)
 
208
     *            position of the Strings Entry for this node. This will change
 
209
     *            from one call to the other if we're writing String
 
210
     *            StateValues.
 
211
     * @return The size of the Strings Entry that was written, if any.
 
212
     */
 
213
    int writeInterval(ByteBuffer buffer, int endPosOfStringEntry) {
 
214
        buffer.putLong(start);
 
215
        buffer.putLong(end);
 
216
        buffer.putInt(attribute);
 
217
        buffer.put(getByteFromType(sv.getType()));
 
218
 
 
219
        switch (getByteFromType(sv.getType())) {
 
220
 
 
221
        case TYPE_NULL:
 
222
        case TYPE_INTEGER:
 
223
            /* We write the 'valueOffset' field as a straight value. In the case
 
224
             * of a null value, it will be unboxed as -1 */
 
225
            try {
 
226
                buffer.putInt(sv.unboxInt());
 
227
            } catch (StateValueTypeException e) {
 
228
                /*
 
229
                 * This should not happen, since the value told us it was of
 
230
                 * type Null or Integer (corrupted value?)
 
231
                 */
 
232
                e.printStackTrace();
 
233
            }
 
234
            break;
 
235
 
 
236
        case TYPE_STRING:
 
237
            byte[] byteArrayToWrite;
 
238
            try {
 
239
                byteArrayToWrite = sv.unboxStr().getBytes();
 
240
            } catch (StateValueTypeException e1) {
 
241
                /* Should not happen, we're in a switch/case for string type */
 
242
                throw new RuntimeException();
 
243
            }
 
244
 
 
245
            /* we use the valueOffset as an offset. */
 
246
            buffer.putInt(endPosOfStringEntry - stringsEntrySize);
 
247
            buffer.mark();
 
248
            buffer.position(endPosOfStringEntry - stringsEntrySize);
 
249
 
 
250
            /*
 
251
             * write the Strings entry (1st byte = size, then the bytes, then the 0)
 
252
             */
 
253
            buffer.put((byte) stringsEntrySize);
 
254
            buffer.put(byteArrayToWrite);
 
255
            buffer.put((byte) 0);
 
256
            assert (buffer.position() == endPosOfStringEntry);
 
257
            buffer.reset();
 
258
            break;
 
259
 
 
260
        case TYPE_LONG:
 
261
            /* we use the valueOffset as an offset. */
 
262
            buffer.putInt(endPosOfStringEntry - stringsEntrySize);
 
263
            buffer.mark();
 
264
            buffer.position(endPosOfStringEntry - stringsEntrySize);
 
265
 
 
266
            /*
 
267
             * write the Long in the Strings section
 
268
             */
 
269
            try {
 
270
                buffer.putLong(sv.unboxLong());
 
271
            } catch (StateValueTypeException e) {
 
272
                /*
 
273
                 * This should not happen, since the value told us it was of
 
274
                 * type Long (corrupted value?)
 
275
                 */
 
276
                e.printStackTrace();
 
277
            }
 
278
            assert (buffer.position() == endPosOfStringEntry);
 
279
            buffer.reset();
 
280
            break;
 
281
 
 
282
        default:
 
283
            break;
 
284
        }
 
285
        return stringsEntrySize;
 
286
    }
 
287
 
 
288
    @Override
 
289
    public long getStartTime() {
 
290
        return start;
 
291
    }
 
292
 
 
293
    @Override
 
294
    public long getEndTime() {
 
295
        return end;
 
296
    }
 
297
 
 
298
    @Override
 
299
    public long getViewerEndTime() {
 
300
        return end + 1;
 
301
    }
 
302
 
 
303
    @Override
 
304
    public int getAttribute() {
 
305
        return attribute;
 
306
    }
 
307
 
 
308
    @Override
 
309
    public ITmfStateValue getStateValue() {
 
310
        return sv;
 
311
    }
 
312
 
 
313
    @Override
 
314
    public boolean intersects(long timestamp) {
 
315
        if (start <= timestamp) {
 
316
            if (end >= timestamp) {
 
317
                return true;
 
318
            }
 
319
        }
 
320
        return false;
 
321
    }
 
322
 
 
323
    int getStringsEntrySize() {
 
324
        return stringsEntrySize;
 
325
    }
 
326
 
 
327
    /**
 
328
     * Total serialized size of this interval
 
329
     *
 
330
     * @return
 
331
     */
 
332
    int getIntervalSize() {
 
333
        return stringsEntrySize + HTNode.DATA_ENTRY_SIZE;
 
334
    }
 
335
 
 
336
    private int computeStringsEntrySize() {
 
337
        switch(sv.getType()) {
 
338
        case NULL:
 
339
        case INTEGER:
 
340
            /* Those don't use the strings section at all */
 
341
            return NO_ENTRY_SIZE;
 
342
        case LONG:
 
343
            /* The value's bytes are written directly into the strings section */
 
344
            return LONG_ENTRY_SIZE;
 
345
        case STRING:
 
346
            try {
 
347
                /* String's length + 2 (1 byte for size, 1 byte for \0 at the end */
 
348
                return sv.unboxStr().getBytes().length + 2;
 
349
            } catch (StateValueTypeException e) {
 
350
                /* We're inside a switch/case for the string type, can't happen */
 
351
                throw new IllegalStateException(e);
 
352
            }
 
353
        default:
 
354
            /* It's very important that we know how to write the state value in
 
355
             * the file!! */
 
356
            throw new IllegalStateException();
 
357
        }
 
358
    }
 
359
 
 
360
    /**
 
361
     * Compare the END TIMES of different intervals. This is used to sort the
 
362
     * intervals when we close down a node.
 
363
     */
 
364
    @Override
 
365
    public int compareTo(HTInterval other) {
 
366
        if (this.end < other.end) {
 
367
            return -1;
 
368
        } else if (this.end > other.end) {
 
369
            return 1;
 
370
        } else {
 
371
            return 0;
 
372
        }
 
373
    }
 
374
 
 
375
    @Override
 
376
    public boolean equals(Object other) {
 
377
        if (other instanceof HTInterval &&
 
378
                this.compareTo((HTInterval) other) == 0) {
 
379
            return true;
 
380
        }
 
381
        return false;
 
382
    }
 
383
 
 
384
    @Override
 
385
    public int hashCode() {
 
386
        return super.hashCode();
 
387
    }
 
388
 
 
389
    @Override
 
390
    public String toString() {
 
391
        /* Only for debug, should not be externalized */
 
392
        StringBuilder sb = new StringBuilder();
 
393
        sb.append('[');
 
394
        sb.append(start);
 
395
        sb.append(", "); //$NON-NLS-1$
 
396
        sb.append(end);
 
397
        sb.append(']');
 
398
 
 
399
        sb.append(", attribute = "); //$NON-NLS-1$
 
400
        sb.append(attribute);
 
401
 
 
402
        sb.append(", value = "); //$NON-NLS-1$
 
403
        sb.append(sv.toString());
 
404
 
 
405
        return sb.toString();
 
406
    }
 
407
 
 
408
    /**
 
409
     * Here we determine how state values "types" are written in the 8-bit
 
410
     * field that indicates the value type in the file.
 
411
     */
 
412
    private static byte getByteFromType(ITmfStateValue.Type type) {
 
413
        switch(type) {
 
414
        case NULL:
 
415
            return TYPE_NULL;
 
416
        case INTEGER:
 
417
            return TYPE_INTEGER;
 
418
        case STRING:
 
419
            return TYPE_STRING;
 
420
        case LONG:
 
421
            return TYPE_LONG;
 
422
        default:
 
423
            /* Should not happen if the switch is fully covered */
 
424
            throw new IllegalStateException();
 
425
        }
 
426
    }
 
427
}