Commit | Line | Data |
---|---|---|
f9a76cac AM |
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 | ||
cb42195c | 44 | private static final Comparator<ITmfStateInterval> END_COMPARATOR = |
f9a76cac AM |
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); | |
cb42195c | 184 | int mid = Collections.binarySearch(list, dummyInterval, END_COMPARATOR); |
f9a76cac AM |
185 | |
186 | /* The returned value is < 0 if the exact key was not found. */ | |
187 | if (mid < 0) { | |
188 | mid = -mid; | |
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 | } |