1 /*******************************************************************************
2 * Copyright (c) 2013, 2015 Ericsson
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
10 * Alexandre Montplaisir - Initial API and implementation
11 * Matthew Khouzam - Modified to use a TreeSet
12 * Patrick Tasse - Add message to exceptions
13 ******************************************************************************/
15 package org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
;
18 import java
.io
.FileInputStream
;
19 import java
.io
.PrintWriter
;
20 import java
.util
.Comparator
;
21 import java
.util
.Iterator
;
22 import java
.util
.List
;
23 import java
.util
.NavigableSet
;
24 import java
.util
.SortedSet
;
25 import java
.util
.TreeSet
;
27 import org
.eclipse
.jdt
.annotation
.NonNull
;
28 import org
.eclipse
.tracecompass
.statesystem
.core
.backend
.IStateHistoryBackend
;
29 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
30 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
31 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
32 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.TmfStateInterval
;
33 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
34 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
37 * State history back-end that stores its intervals in RAM only. It cannot be
38 * saved to disk, which means we need to rebuild it every time we re-open a
39 * trace. But it's relatively quick to build, so this shouldn't be a problem in
42 * This should only be used with very small state histories (and/or, very small
43 * traces). Since it's stored in standard Collections, it's limited to 2^31
46 * @author Alexandre Montplaisir
48 public class InMemoryBackend
implements IStateHistoryBackend
{
51 * We need to compare the end time and the attribute, because we can have 2
52 * intervals with the same end time (for different attributes). And TreeSet
53 * needs a unique "key" per element.
55 private static final Comparator
<ITmfStateInterval
> END_COMPARATOR
=
56 new Comparator
<ITmfStateInterval
>() {
58 public int compare(ITmfStateInterval o1
, ITmfStateInterval o2
) {
59 final long e1
= o1
.getEndTime();
60 final long e2
= o2
.getEndTime();
61 final int a1
= o1
.getAttribute();
62 final int a2
= o2
.getAttribute();
78 private final @NonNull String ssid
;
79 private final NavigableSet
<ITmfStateInterval
> intervals
;
80 private final long startTime
;
82 private volatile long latestTime
;
88 * The state system's ID
90 * The start time of this interval store
92 public InMemoryBackend(@NonNull String ssid
, long startTime
) {
94 this.startTime
= startTime
;
95 this.latestTime
= startTime
;
96 this.intervals
= new TreeSet
<>(END_COMPARATOR
);
100 public String
getSSID() {
105 public long getStartTime() {
110 public long getEndTime() {
115 public void insertPastState(long stateStartTime
, long stateEndTime
,
116 int quark
, ITmfStateValue value
) throws TimeRangeException
{
117 /* Make sure the passed start/end times make sense */
118 if (stateStartTime
> stateEndTime
|| stateStartTime
< startTime
) {
119 throw new TimeRangeException(ssid
+ " Interval Start:" + stateStartTime
+ ", Interval End:" + stateEndTime
+ ", Backend Start:" + startTime
); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
122 ITmfStateInterval interval
= new TmfStateInterval(stateStartTime
, stateEndTime
, quark
, value
);
124 /* Add the interval into the tree */
125 synchronized (intervals
) {
126 intervals
.add(interval
);
129 /* Update the "latest seen time" */
130 if (stateEndTime
> latestTime
) {
131 latestTime
= stateEndTime
;
136 public void doQuery(List
<ITmfStateInterval
> currentStateInfo
, long t
)
137 throws TimeRangeException
{
138 if (!checkValidTime(t
)) {
139 throw new TimeRangeException(ssid
+ " Time:" + t
+ ", Start:" + startTime
+ ", End:" + latestTime
); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
143 * The intervals are sorted by end time, so we can binary search to get
144 * the first possible interval, then only compare their start times.
146 synchronized (intervals
) {
147 Iterator
<ITmfStateInterval
> iter
= searchforEndTime(intervals
, t
);
148 for (int modCount
= 0; iter
.hasNext() && modCount
< currentStateInfo
.size();) {
149 ITmfStateInterval entry
= iter
.next();
150 final long entryStartTime
= entry
.getStartTime();
151 if (entryStartTime
<= t
) {
152 /* Add this interval to the returned values */
153 currentStateInfo
.set(entry
.getAttribute(), entry
);
161 public ITmfStateInterval
doSingularQuery(long t
, int attributeQuark
)
162 throws TimeRangeException
, AttributeNotFoundException
{
163 if (!checkValidTime(t
)) {
164 throw new TimeRangeException(ssid
+ " Time:" + t
+ ", Start:" + startTime
+ ", End:" + latestTime
); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
168 * The intervals are sorted by end time, so we can binary search to get
169 * the first possible interval, then only compare their start times.
171 synchronized (intervals
) {
172 Iterator
<ITmfStateInterval
> iter
= searchforEndTime(intervals
, t
);
173 while (iter
.hasNext()) {
174 ITmfStateInterval entry
= iter
.next();
175 final boolean attributeMatches
= (entry
.getAttribute() == attributeQuark
);
176 final long entryStartTime
= entry
.getStartTime();
177 if (attributeMatches
) {
178 if (entryStartTime
<= t
) {
179 /* This is the droid we are looking for */
185 throw new AttributeNotFoundException(ssid
+ " Quark:" + attributeQuark
); //$NON-NLS-1$
188 private boolean checkValidTime(long t
) {
189 if (t
>= startTime
&& t
<= latestTime
) {
196 public void finishedBuilding(long endTime
) throws TimeRangeException
{
201 public FileInputStream
supplyAttributeTreeReader() {
202 /* Saving to disk not supported */
207 public File
supplyAttributeTreeWriterFile() {
208 /* Saving to disk not supported */
213 public long supplyAttributeTreeWriterFilePosition() {
214 /* Saving to disk not supported */
219 public void removeFiles() {
224 public void dispose() {
229 public void debugPrint(PrintWriter writer
) {
230 synchronized (intervals
) {
231 writer
.println(intervals
.toString());
235 private static Iterator
<ITmfStateInterval
> searchforEndTime(NavigableSet
<ITmfStateInterval
> tree
, long time
) {
236 ITmfStateInterval dummyInterval
= new TmfStateInterval(-1, time
, -1, TmfStateValue
.nullValue());
237 ITmfStateInterval myInterval
= tree
.lower(dummyInterval
);
238 if (myInterval
== null) {
239 return tree
.iterator();
241 final SortedSet
<ITmfStateInterval
> tailSet
= tree
.tailSet(myInterval
);
242 Iterator
<ITmfStateInterval
> retVal
= tailSet
.iterator();