Commit | Line | Data |
---|---|---|
f9a76cac | 1 | /******************************************************************************* |
60ae41e1 | 2 | * Copyright (c) 2013, 2014 Ericsson |
f9a76cac AM |
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 | |
f606c6fa | 11 | * Matthew Khouzam - Modified to use a TreeSet |
f9a76cac AM |
12 | ******************************************************************************/ |
13 | ||
14 | package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends; | |
15 | ||
16 | import java.io.File; | |
17 | import java.io.FileInputStream; | |
18 | import java.io.PrintWriter; | |
f9a76cac | 19 | import java.util.Comparator; |
f606c6fa | 20 | import java.util.Iterator; |
f9a76cac | 21 | import java.util.List; |
f606c6fa MK |
22 | import java.util.SortedSet; |
23 | import java.util.TreeSet; | |
f9a76cac AM |
24 | |
25 | import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException; | |
26 | import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException; | |
27 | import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval; | |
f9a76cac AM |
28 | import org.eclipse.linuxtools.tmf.core.interval.TmfStateInterval; |
29 | import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue; | |
30 | ||
31 | /** | |
32 | * State history back-end that stores its intervals in RAM only. It cannot be | |
33 | * saved to disk, which means we need to rebuild it every time we re-open a | |
34 | * trace. But it's relatively quick to build, so this shouldn't be a problem in | |
35 | * most cases. | |
36 | * | |
37 | * This should only be used with very small state histories (and/or, very small | |
38 | * traces). Since it's stored in standard Collections, it's limited to 2^31 | |
39 | * intervals. | |
40 | * | |
41 | * @author Alexandre Montplaisir | |
42 | */ | |
43 | public class InMemoryBackend implements IStateHistoryBackend { | |
44 | ||
f606c6fa MK |
45 | /** |
46 | * We need to compare the end time and the attribute, because we can have 2 | |
47 | * intervals with the same end time (for different attributes). And TreeSet | |
48 | * needs a unique "key" per element. | |
49 | */ | |
cb42195c | 50 | private static final Comparator<ITmfStateInterval> END_COMPARATOR = |
f606c6fa MK |
51 | new Comparator<ITmfStateInterval>() { |
52 | @Override | |
53 | public int compare(ITmfStateInterval o1, ITmfStateInterval o2) { | |
54 | final long e1 = o1.getEndTime(); | |
55 | final long e2 = o2.getEndTime(); | |
56 | final int a1 = o1.getAttribute(); | |
57 | final int a2 = o2.getAttribute(); | |
58 | if (e1 < e2) { | |
59 | return -1; | |
60 | } else if (e1 > e2) { | |
61 | return 1; | |
62 | } else if (a1 < a2) { | |
63 | return -1; | |
64 | } else if (a1 > a2) { | |
65 | return 1; | |
66 | } else { | |
67 | return 0; | |
68 | } | |
69 | } | |
f9a76cac | 70 | |
f606c6fa MK |
71 | }; |
72 | ||
73 | private final TreeSet<ITmfStateInterval> intervals; | |
f9a76cac | 74 | private final long startTime; |
eaf12e04 | 75 | private volatile long latestTime; |
f9a76cac AM |
76 | |
77 | /** | |
78 | * Constructor | |
79 | * | |
80 | * @param startTime | |
81 | * The start time of this interval store | |
82 | */ | |
83 | public InMemoryBackend(long startTime) { | |
84 | this.startTime = startTime; | |
85 | this.latestTime = startTime; | |
a4524c1b | 86 | this.intervals = new TreeSet<>(END_COMPARATOR); |
f9a76cac AM |
87 | } |
88 | ||
89 | @Override | |
90 | public long getStartTime() { | |
91 | return startTime; | |
92 | } | |
93 | ||
94 | @Override | |
95 | public long getEndTime() { | |
96 | return latestTime; | |
97 | } | |
98 | ||
99 | @Override | |
100 | public void insertPastState(long stateStartTime, long stateEndTime, | |
101 | int quark, ITmfStateValue value) throws TimeRangeException { | |
102 | /* Make sure the passed start/end times make sense */ | |
103 | if (stateStartTime > stateEndTime || stateStartTime < startTime) { | |
104 | throw new TimeRangeException(); | |
105 | } | |
106 | ||
107 | ITmfStateInterval interval = new TmfStateInterval(stateStartTime, stateEndTime, quark, value); | |
108 | ||
eaf12e04 AM |
109 | /* Add the interval into the tree */ |
110 | synchronized (intervals) { | |
111 | intervals.add(interval); | |
112 | } | |
113 | ||
f9a76cac AM |
114 | /* Update the "latest seen time" */ |
115 | if (stateEndTime > latestTime) { | |
116 | latestTime = stateEndTime; | |
117 | } | |
f9a76cac AM |
118 | } |
119 | ||
f9a76cac AM |
120 | @Override |
121 | public void doQuery(List<ITmfStateInterval> currentStateInfo, long t) | |
122 | throws TimeRangeException { | |
123 | if (!checkValidTime(t)) { | |
124 | throw new TimeRangeException(); | |
125 | } | |
126 | ||
127 | /* | |
128 | * The intervals are sorted by end time, so we can binary search to get | |
129 | * the first possible interval, then only compare their start times. | |
130 | */ | |
eaf12e04 AM |
131 | synchronized (intervals) { |
132 | Iterator<ITmfStateInterval> iter = serachforEndTime(intervals, t); | |
133 | for (int modCount = 0; iter.hasNext() && modCount < currentStateInfo.size();) { | |
134 | ITmfStateInterval entry = iter.next(); | |
135 | final long entryStartTime = entry.getStartTime(); | |
136 | if (entryStartTime <= t) { | |
137 | /* Add this interval to the returned values */ | |
138 | currentStateInfo.set(entry.getAttribute(), entry); | |
139 | modCount++; | |
140 | } | |
f9a76cac AM |
141 | } |
142 | } | |
143 | } | |
144 | ||
145 | @Override | |
146 | public ITmfStateInterval doSingularQuery(long t, int attributeQuark) | |
147 | throws TimeRangeException, AttributeNotFoundException { | |
148 | if (!checkValidTime(t)) { | |
149 | throw new TimeRangeException(); | |
150 | } | |
151 | ||
152 | /* | |
153 | * The intervals are sorted by end time, so we can binary search to get | |
154 | * the first possible interval, then only compare their start times. | |
155 | */ | |
eaf12e04 AM |
156 | synchronized (intervals) { |
157 | Iterator<ITmfStateInterval> iter = serachforEndTime(intervals, t); | |
158 | while (iter.hasNext()) { | |
159 | ITmfStateInterval entry = iter.next(); | |
160 | final boolean attributeMatches = (entry.getAttribute() == attributeQuark); | |
161 | final long entryStartTime = entry.getStartTime(); | |
162 | if (attributeMatches) { | |
163 | if (entryStartTime <= t) { | |
164 | /* This is the droid we are looking for */ | |
165 | return entry; | |
166 | } | |
f9a76cac | 167 | } |
f606c6fa | 168 | } |
f9a76cac AM |
169 | } |
170 | throw new AttributeNotFoundException(); | |
171 | } | |
172 | ||
173 | @Override | |
174 | public boolean checkValidTime(long t) { | |
175 | if (t >= startTime && t <= latestTime) { | |
176 | return true; | |
177 | } | |
178 | return false; | |
179 | } | |
180 | ||
181 | @Override | |
182 | public void finishedBuilding(long endTime) throws TimeRangeException { | |
183 | /* Nothing to do */ | |
184 | } | |
185 | ||
186 | @Override | |
187 | public FileInputStream supplyAttributeTreeReader() { | |
188 | /* Saving to disk not supported */ | |
189 | return null; | |
190 | } | |
191 | ||
192 | @Override | |
193 | public File supplyAttributeTreeWriterFile() { | |
194 | /* Saving to disk not supported */ | |
195 | return null; | |
196 | } | |
197 | ||
198 | @Override | |
199 | public long supplyAttributeTreeWriterFilePosition() { | |
200 | /* Saving to disk not supported */ | |
201 | return -1; | |
202 | } | |
203 | ||
204 | @Override | |
205 | public void removeFiles() { | |
206 | /* Nothing to do */ | |
207 | } | |
208 | ||
209 | @Override | |
210 | public void dispose() { | |
211 | /* Nothing to do */ | |
212 | } | |
213 | ||
214 | @Override | |
215 | public void debugPrint(PrintWriter writer) { | |
eaf12e04 AM |
216 | synchronized (intervals) { |
217 | writer.println(intervals.toString()); | |
218 | } | |
f9a76cac AM |
219 | } |
220 | ||
f606c6fa | 221 | private static Iterator<ITmfStateInterval> serachforEndTime(TreeSet<ITmfStateInterval> tree, long time) { |
f9a76cac | 222 | ITmfStateInterval dummyInterval = new TmfStateInterval(-1, time, -1, null); |
f606c6fa MK |
223 | ITmfStateInterval myInterval = tree.lower(dummyInterval); |
224 | if (myInterval == null) { | |
225 | return tree.iterator(); | |
f9a76cac | 226 | } |
f606c6fa MK |
227 | final SortedSet<ITmfStateInterval> tailSet = tree.tailSet(myInterval); |
228 | Iterator<ITmfStateInterval> retVal = tailSet.iterator(); | |
229 | retVal.next(); | |
230 | return retVal; | |
f9a76cac AM |
231 | } |
232 | ||
233 | } |