tmf : Fix binary search end time in InMemoryBackend
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / backends / InMemoryBackend.java
1 /*******************************************************************************
2 * Copyright (c) 2013 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Alexandre Montplaisir - Initial API and implementation
11 ******************************************************************************/
12
13 package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends;
14
15 import java.io.File;
16 import java.io.FileInputStream;
17 import java.io.PrintWriter;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.Comparator;
21 import java.util.List;
22
23 import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
24 import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
25 import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
26 import org.eclipse.linuxtools.tmf.core.interval.TmfIntervalEndComparator;
27 import org.eclipse.linuxtools.tmf.core.interval.TmfStateInterval;
28 import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
29
30 /**
31 * State history back-end that stores its intervals in RAM only. It cannot be
32 * saved to disk, which means we need to rebuild it every time we re-open a
33 * trace. But it's relatively quick to build, so this shouldn't be a problem in
34 * most cases.
35 *
36 * This should only be used with very small state histories (and/or, very small
37 * traces). Since it's stored in standard Collections, it's limited to 2^31
38 * intervals.
39 *
40 * @author Alexandre Montplaisir
41 */
42 public class InMemoryBackend implements IStateHistoryBackend {
43
44 private static final Comparator<ITmfStateInterval> END_COMPARATOR =
45 new TmfIntervalEndComparator();
46
47 private final List<ITmfStateInterval> intervals;
48 private final long startTime;
49 private long latestTime;
50
51 /**
52 * Constructor
53 *
54 * @param startTime
55 * The start time of this interval store
56 */
57 public InMemoryBackend(long startTime) {
58 this.startTime = startTime;
59 this.latestTime = startTime;
60 this.intervals = new ArrayList<ITmfStateInterval>();
61 }
62
63 @Override
64 public long getStartTime() {
65 return startTime;
66 }
67
68 @Override
69 public long getEndTime() {
70 return latestTime;
71 }
72
73 @Override
74 public void insertPastState(long stateStartTime, long stateEndTime,
75 int quark, ITmfStateValue value) throws TimeRangeException {
76 /* Make sure the passed start/end times make sense */
77 if (stateStartTime > stateEndTime || stateStartTime < startTime) {
78 throw new TimeRangeException();
79 }
80
81 ITmfStateInterval interval = new TmfStateInterval(stateStartTime, stateEndTime, quark, value);
82
83 /* Update the "latest seen time" */
84 if (stateEndTime > latestTime) {
85 latestTime = stateEndTime;
86 }
87
88 /* Add the interval into the-array */
89 intervals.add(interval);
90 }
91
92
93 @Override
94 public void doQuery(List<ITmfStateInterval> currentStateInfo, long t)
95 throws TimeRangeException {
96 if (!checkValidTime(t)) {
97 throw new TimeRangeException();
98 }
99
100 /*
101 * The intervals are sorted by end time, so we can binary search to get
102 * the first possible interval, then only compare their start times.
103 */
104 ITmfStateInterval entry;
105 for (int i = binarySearchEndTime(intervals, t); i < intervals.size(); i++) {
106 entry = intervals.get(i);
107 if (entry.getStartTime() <= t) {
108 /* Add this interval to the returned values */
109 currentStateInfo.set(entry.getAttribute(), entry);
110 }
111 }
112 }
113
114 @Override
115 public ITmfStateInterval doSingularQuery(long t, int attributeQuark)
116 throws TimeRangeException, AttributeNotFoundException {
117 if (!checkValidTime(t)) {
118 throw new TimeRangeException();
119 }
120
121 /*
122 * The intervals are sorted by end time, so we can binary search to get
123 * the first possible interval, then only compare their start times.
124 */
125 ITmfStateInterval entry;
126 for (int i = binarySearchEndTime(intervals, t); i < intervals.size(); i++) {
127 entry = intervals.get(i);
128 if (entry.getStartTime() <= t && entry.getAttribute() == attributeQuark) {
129 /* This is the droid we are looking for */
130 return entry;
131 }
132 }
133 throw new AttributeNotFoundException();
134 }
135
136 @Override
137 public boolean checkValidTime(long t) {
138 if (t >= startTime && t <= latestTime) {
139 return true;
140 }
141 return false;
142 }
143
144 @Override
145 public void finishedBuilding(long endTime) throws TimeRangeException {
146 /* Nothing to do */
147 }
148
149 @Override
150 public FileInputStream supplyAttributeTreeReader() {
151 /* Saving to disk not supported */
152 return null;
153 }
154
155 @Override
156 public File supplyAttributeTreeWriterFile() {
157 /* Saving to disk not supported */
158 return null;
159 }
160
161 @Override
162 public long supplyAttributeTreeWriterFilePosition() {
163 /* Saving to disk not supported */
164 return -1;
165 }
166
167 @Override
168 public void removeFiles() {
169 /* Nothing to do */
170 }
171
172 @Override
173 public void dispose() {
174 /* Nothing to do */
175 }
176
177 @Override
178 public void debugPrint(PrintWriter writer) {
179 writer.println(intervals.toString());
180 }
181
182 private static int binarySearchEndTime(List<ITmfStateInterval> list, long time) {
183 ITmfStateInterval dummyInterval = new TmfStateInterval(-1, time, -1, null);
184 int mid = Collections.binarySearch(list, dummyInterval, END_COMPARATOR);
185
186 /* The returned value is < 0 if the exact key was not found. */
187 if (mid < 0) {
188 mid = -mid - 1;
189 }
190
191 /*
192 * Collections.binarySearch doesn't guarantee which element is returned
193 * if it falls on one of many equal ones. So make sure we are at the
194 * first one provided.
195 */
196 while ((mid > 0) &&
197 (list.get(mid).getEndTime() == list.get(mid-1).getEndTime())) {
198 mid--;
199 }
200 return mid;
201 }
202
203 }
This page took 0.055014 seconds and 5 git commands to generate.