Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 5312c62812e7d714794f667c677983dd6d6b448d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
/*******************************************************************************
 * Copyright (c) 2012 Ericsson
 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
 *
 * All rights reserved. This program and the accompanying materials are
 * made available under the terms of the Eclipse Public License v1.0 which
 * accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 *******************************************************************************/

package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree;

import java.io.IOException;
import java.nio.ByteBuffer;

import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;

/**
 * The interval component, which will be contained in a node of the History
 * Tree.
 *
 * @author alexmont
 *
 */
final class HTInterval implements ITmfStateInterval, Comparable<HTInterval> {

    private final long start;
    private final long end;
    private final int attribute;
    private final TmfStateValue sv;

    /*
     * Size of the strings section entry used by this interval (= 0 if not used)
     */
    private final int stringsEntrySize;

    /**
     * Standard constructor
     *
     * @param intervalStart
     * @param intervalEnd
     * @param attribute
     * @param value
     * @throws TimeRangeException
     */
    HTInterval(long intervalStart, long intervalEnd, int attribute,
            TmfStateValue value) throws TimeRangeException {
        if (intervalStart > intervalEnd) {
            throw new TimeRangeException();
        }

        this.start = intervalStart;
        this.end = intervalEnd;
        this.attribute = attribute;
        this.sv = value;
        this.stringsEntrySize = computeStringsEntrySize();
    }

    /**
     * Reader constructor. Builds the interval using an already-allocated
     * ByteBuffer, which normally comes from a NIO FileChannel.
     *
     * @param buffer
     *            The ByteBuffer from which to read the information
     * @throws IOException
     */
    final static HTInterval readFrom(ByteBuffer buffer) throws IOException {
        HTInterval interval;
        long intervalStart, intervalEnd;
        int attribute;
        TmfStateValue value;
        int valueOrOffset, valueSize, res;
        byte valueType;
        byte array[];

        /* Read the Data Section entry */
        intervalStart = buffer.getLong();
        intervalEnd = buffer.getLong();
        attribute = buffer.getInt();

        /* Read the 'type' of the value, then react accordingly */
        valueType = buffer.get();
        if (valueType <= 0) {
            /* the type of ValueOrOffset is 'value' */
            valueOrOffset = buffer.getInt();
            if (valueOrOffset == -1) {
                /* Null value */
                value = TmfStateValue.nullValue();
            } else {
                /* Normal integer value */
                value = TmfStateValue.newValueInt(valueOrOffset);
            }

        } else { // valueType > 0
            /* the type is 'offset' */
            valueOrOffset = buffer.getInt();

            /*
             * Go read the corresponding entry in the Strings section of the
             * block
             */
            buffer.mark();
            buffer.position(valueOrOffset);

            /* the first byte = the size to read */
            valueSize = buffer.get();

            /*
             * Careful though, 'valueSize' is the total size of the entry,
             * including the 'size' byte at the start and end (0'ed) byte at the
             * end. Here we want 'array' to only contain the real payload of the
             * value.
             */
            array = new byte[valueSize - 2];
            buffer.get(array);
            value = TmfStateValue.newValueString(new String(array));

            /* Confirm the 0'ed byte at the end */
            res = buffer.get();
            if (res != 0) {
                throw new IOException(
                        "Invalid interval data. Maybe your file is corrupt?"); //$NON-NLS-1$
            }

            /*
             * Restore the file pointer's position (so we can read the next
             * interval)
             */
            buffer.reset();
        }

        try {
            interval = new HTInterval(intervalStart, intervalEnd, attribute,
                    value);
        } catch (TimeRangeException e) {
            throw new IOException(
                    "Invalid interval data. Maybe your file is corrupt?"); //$NON-NLS-1$
        }
        return interval;
    }

    /**
     * Antagonist of the previous constructor, write the Data entry
     * corresponding to this interval in a ByteBuffer (mapped to a block in the
     * history-file, hopefully)
     *
     * @param buffer
     *            The already-allocated ByteBuffer corresponding to a SHT Node
     * @param endPosOfStringEntry
     *            The initial (before calling this function for this interval)
     *            position of the Strings Entry for this node. This will change
     *            from one call to the other if we're writing String
     *            StateValues.
     * @return The size of the Strings Entry that was written, if any.
     */
    int writeInterval(ByteBuffer buffer, int endPosOfStringEntry) {
        int sizeOfStringEntry;
        byte[] byteArrayToWrite;

        buffer.putLong(start);
        buffer.putLong(end);
        buffer.putInt(attribute);
        buffer.put(sv.getType());

        byteArrayToWrite = sv.toByteArray();

        if (byteArrayToWrite == null) {
            /* We write the 'valueOffset' field as a straight value. In the case
             * of a null value, it will be unboxed as -1 */
            try {
                buffer.putInt(sv.unboxInt());
            } catch (StateValueTypeException e) {
                /*
                 * This should not happen, since the value told us it was of
                 * type Null or Integer (corrupted value?)
                 */
                e.printStackTrace();
            }
            return 0; /* we didn't use a Strings section entry */

        }
        /*
         * Size to write (+2 = +1 for size at the start, +1 for the 0 at the
         * end)
         */
        sizeOfStringEntry = byteArrayToWrite.length + 2;

        /* we use the valueOffset as an offset. */
        buffer.putInt(endPosOfStringEntry - sizeOfStringEntry);
        buffer.mark();
        buffer.position(endPosOfStringEntry - sizeOfStringEntry);

        /*
         * write the Strings entry (1st byte = size, then the bytes, then the 0)
         */
        buffer.put((byte) sizeOfStringEntry);
        buffer.put(byteArrayToWrite);
        buffer.put((byte) 0);
        assert (buffer.position() == endPosOfStringEntry);
        buffer.reset();
        return sizeOfStringEntry;
    }

    @Override
    public long getStartTime() {
        return start;
    }

    @Override
    public long getEndTime() {
        return end;
    }

    @Override
    public long getViewerEndTime() {
        return end + 1;
    }

    @Override
    public int getAttribute() {
        return attribute;
    }

    @Override
    public ITmfStateValue getStateValue() {
        return sv;
    }

    @Override
    public boolean intersects(long timestamp) {
        if (start <= timestamp) {
            if (end >= timestamp) {
                return true;
            }
        }
        return false;
    }

    int getStringsEntrySize() {
        return stringsEntrySize;
    }

    /**
     * Total serialized size of this interval
     *
     * @return
     */
    int getIntervalSize() {
        return stringsEntrySize + HTNode.getDataEntrySize();
    }

    private int computeStringsEntrySize() {
        if (sv.toByteArray() == null) {
            return 0;
        }
        return sv.toByteArray().length + 2;
        /* (+1 for the first byte indicating the size, +1 for the 0'ed byte) */
    }

    /**
     * Compare the END TIMES of different intervals. This is used to sort the
     * intervals when we close down a node.
     */
    @Override
    public int compareTo(HTInterval other) {
        if (this.end < other.end) {
            return -1;
        } else if (this.end > other.end) {
            return 1;
        } else {
            return 0;
        }
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof HTInterval) {
            if (this.compareTo((HTInterval) other) == 0) {
                return true;
            }
        }
        return false;
    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }

    @Override
    public String toString() {
        /* Only for debug, should not be externalized */
        StringBuilder sb = new StringBuilder();
        sb.append('[');
        sb.append(start);
        sb.append(", "); //$NON-NLS-1$
        sb.append(end);
        sb.append(']');

        sb.append(", attribute = "); //$NON-NLS-1$
        sb.append(attribute);

        sb.append(", value = "); //$NON-NLS-1$
        sb.append(sv.toString());

        return sb.toString();
    }
}

Back to the top