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
.SortedSet
;
24 import java
.util
.TreeSet
;
26 import org
.eclipse
.jdt
.annotation
.NonNull
;
27 import org
.eclipse
.tracecompass
.statesystem
.core
.backend
.IStateHistoryBackend
;
28 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
29 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
30 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
31 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.TmfStateInterval
;
32 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
33 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
36 * State history back-end that stores its intervals in RAM only. It cannot be
37 * saved to disk, which means we need to rebuild it every time we re-open a
38 * trace. But it's relatively quick to build, so this shouldn't be a problem in
41 * This should only be used with very small state histories (and/or, very small
42 * traces). Since it's stored in standard Collections, it's limited to 2^31
45 * @author Alexandre Montplaisir
47 public class InMemoryBackend
implements IStateHistoryBackend
{
50 * We need to compare the end time and the attribute, because we can have 2
51 * intervals with the same end time (for different attributes). And TreeSet
52 * needs a unique "key" per element.
54 private static final Comparator
<ITmfStateInterval
> END_COMPARATOR
=
55 new Comparator
<ITmfStateInterval
>() {
57 public int compare(ITmfStateInterval o1
, ITmfStateInterval o2
) {
58 final long e1
= o1
.getEndTime();
59 final long e2
= o2
.getEndTime();
60 final int a1
= o1
.getAttribute();
61 final int a2
= o2
.getAttribute();
77 private final @NonNull String ssid
;
78 private final TreeSet
<ITmfStateInterval
> intervals
;
79 private final long startTime
;
81 private volatile long latestTime
;
87 * The state system's ID
89 * The start time of this interval store
91 public InMemoryBackend(@NonNull String ssid
, long startTime
) {
93 this.startTime
= startTime
;
94 this.latestTime
= startTime
;
95 this.intervals
= new TreeSet
<>(END_COMPARATOR
);
99 public String
getSSID() {
104 public long getStartTime() {
109 public long getEndTime() {
114 public void insertPastState(long stateStartTime
, long stateEndTime
,
115 int quark
, ITmfStateValue value
) throws TimeRangeException
{
116 /* Make sure the passed start/end times make sense */
117 if (stateStartTime
> stateEndTime
|| stateStartTime
< startTime
) {
118 throw new TimeRangeException(ssid
+ " Interval Start:" + stateStartTime
+ ", Interval End:" + stateEndTime
+ ", Backend Start:" + startTime
); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
121 ITmfStateInterval interval
= new TmfStateInterval(stateStartTime
, stateEndTime
, quark
, value
);
123 /* Add the interval into the tree */
124 synchronized (intervals
) {
125 intervals
.add(interval
);
128 /* Update the "latest seen time" */
129 if (stateEndTime
> latestTime
) {
130 latestTime
= stateEndTime
;
135 public void doQuery(List
<ITmfStateInterval
> currentStateInfo
, long t
)
136 throws TimeRangeException
{
137 if (!checkValidTime(t
)) {
138 throw new TimeRangeException(ssid
+ " Time:" + t
+ ", Start:" + startTime
+ ", End:" + latestTime
); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
142 * The intervals are sorted by end time, so we can binary search to get
143 * the first possible interval, then only compare their start times.
145 synchronized (intervals
) {
146 Iterator
<ITmfStateInterval
> iter
= serachforEndTime(intervals
, t
);
147 for (int modCount
= 0; iter
.hasNext() && modCount
< currentStateInfo
.size();) {
148 ITmfStateInterval entry
= iter
.next();
149 final long entryStartTime
= entry
.getStartTime();
150 if (entryStartTime
<= t
) {
151 /* Add this interval to the returned values */
152 currentStateInfo
.set(entry
.getAttribute(), entry
);
160 public ITmfStateInterval
doSingularQuery(long t
, int attributeQuark
)
161 throws TimeRangeException
, AttributeNotFoundException
{
162 if (!checkValidTime(t
)) {
163 throw new TimeRangeException(ssid
+ " Time:" + t
+ ", Start:" + startTime
+ ", End:" + latestTime
); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
167 * The intervals are sorted by end time, so we can binary search to get
168 * the first possible interval, then only compare their start times.
170 synchronized (intervals
) {
171 Iterator
<ITmfStateInterval
> iter
= serachforEndTime(intervals
, t
);
172 while (iter
.hasNext()) {
173 ITmfStateInterval entry
= iter
.next();
174 final boolean attributeMatches
= (entry
.getAttribute() == attributeQuark
);
175 final long entryStartTime
= entry
.getStartTime();
176 if (attributeMatches
) {
177 if (entryStartTime
<= t
) {
178 /* This is the droid we are looking for */
184 throw new AttributeNotFoundException(ssid
+ " Quark:" + attributeQuark
); //$NON-NLS-1$
187 private boolean checkValidTime(long t
) {
188 if (t
>= startTime
&& t
<= latestTime
) {
195 public void finishedBuilding(long endTime
) throws TimeRangeException
{
200 public FileInputStream
supplyAttributeTreeReader() {
201 /* Saving to disk not supported */
206 public File
supplyAttributeTreeWriterFile() {
207 /* Saving to disk not supported */
212 public long supplyAttributeTreeWriterFilePosition() {
213 /* Saving to disk not supported */
218 public void removeFiles() {
223 public void dispose() {
228 public void debugPrint(PrintWriter writer
) {
229 synchronized (intervals
) {
230 writer
.println(intervals
.toString());
234 private static Iterator
<ITmfStateInterval
> serachforEndTime(TreeSet
<ITmfStateInterval
> tree
, long time
) {
235 ITmfStateInterval dummyInterval
= new TmfStateInterval(-1, time
, -1, TmfStateValue
.nullValue());
236 ITmfStateInterval myInterval
= tree
.lower(dummyInterval
);
237 if (myInterval
== null) {
238 return tree
.iterator();
240 final SortedSet
<ITmfStateInterval
> tailSet
= tree
.tailSet(myInterval
);
241 Iterator
<ITmfStateInterval
> retVal
= tailSet
.iterator();