1 /*******************************************************************************
2 * Copyright (c) 2013, 2014 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 ******************************************************************************/
14 package org
.eclipse
.tracecompass
.statesystem
.core
.backend
;
17 import java
.io
.FileInputStream
;
18 import java
.io
.PrintWriter
;
19 import java
.util
.Comparator
;
20 import java
.util
.Iterator
;
21 import java
.util
.List
;
22 import java
.util
.SortedSet
;
23 import java
.util
.TreeSet
;
25 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
26 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
27 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
28 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.TmfStateInterval
;
29 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
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
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
41 * @author Alexandre Montplaisir
44 public class InMemoryBackend
implements IStateHistoryBackend
{
47 * We need to compare the end time and the attribute, because we can have 2
48 * intervals with the same end time (for different attributes). And TreeSet
49 * needs a unique "key" per element.
51 private static final Comparator
<ITmfStateInterval
> END_COMPARATOR
=
52 new Comparator
<ITmfStateInterval
>() {
54 public int compare(ITmfStateInterval o1
, ITmfStateInterval o2
) {
55 final long e1
= o1
.getEndTime();
56 final long e2
= o2
.getEndTime();
57 final int a1
= o1
.getAttribute();
58 final int a2
= o2
.getAttribute();
74 private final TreeSet
<ITmfStateInterval
> intervals
;
75 private final long startTime
;
76 private volatile long latestTime
;
82 * The start time of this interval store
84 public InMemoryBackend(long startTime
) {
85 this.startTime
= startTime
;
86 this.latestTime
= startTime
;
87 this.intervals
= new TreeSet
<>(END_COMPARATOR
);
91 public long getStartTime() {
96 public long getEndTime() {
101 public void insertPastState(long stateStartTime
, long stateEndTime
,
102 int quark
, ITmfStateValue value
) throws TimeRangeException
{
103 /* Make sure the passed start/end times make sense */
104 if (stateStartTime
> stateEndTime
|| stateStartTime
< startTime
) {
105 throw new TimeRangeException();
108 ITmfStateInterval interval
= new TmfStateInterval(stateStartTime
, stateEndTime
, quark
, value
);
110 /* Add the interval into the tree */
111 synchronized (intervals
) {
112 intervals
.add(interval
);
115 /* Update the "latest seen time" */
116 if (stateEndTime
> latestTime
) {
117 latestTime
= stateEndTime
;
122 public void doQuery(List
<ITmfStateInterval
> currentStateInfo
, long t
)
123 throws TimeRangeException
{
124 if (!checkValidTime(t
)) {
125 throw new TimeRangeException();
129 * The intervals are sorted by end time, so we can binary search to get
130 * the first possible interval, then only compare their start times.
132 synchronized (intervals
) {
133 Iterator
<ITmfStateInterval
> iter
= serachforEndTime(intervals
, t
);
134 for (int modCount
= 0; iter
.hasNext() && modCount
< currentStateInfo
.size();) {
135 ITmfStateInterval entry
= iter
.next();
136 final long entryStartTime
= entry
.getStartTime();
137 if (entryStartTime
<= t
) {
138 /* Add this interval to the returned values */
139 currentStateInfo
.set(entry
.getAttribute(), entry
);
147 public ITmfStateInterval
doSingularQuery(long t
, int attributeQuark
)
148 throws TimeRangeException
, AttributeNotFoundException
{
149 if (!checkValidTime(t
)) {
150 throw new TimeRangeException();
154 * The intervals are sorted by end time, so we can binary search to get
155 * the first possible interval, then only compare their start times.
157 synchronized (intervals
) {
158 Iterator
<ITmfStateInterval
> iter
= serachforEndTime(intervals
, t
);
159 while (iter
.hasNext()) {
160 ITmfStateInterval entry
= iter
.next();
161 final boolean attributeMatches
= (entry
.getAttribute() == attributeQuark
);
162 final long entryStartTime
= entry
.getStartTime();
163 if (attributeMatches
) {
164 if (entryStartTime
<= t
) {
165 /* This is the droid we are looking for */
171 throw new AttributeNotFoundException();
174 private boolean checkValidTime(long t
) {
175 if (t
>= startTime
&& t
<= latestTime
) {
182 public void finishedBuilding(long endTime
) throws TimeRangeException
{
187 public FileInputStream
supplyAttributeTreeReader() {
188 /* Saving to disk not supported */
193 public File
supplyAttributeTreeWriterFile() {
194 /* Saving to disk not supported */
199 public long supplyAttributeTreeWriterFilePosition() {
200 /* Saving to disk not supported */
205 public void removeFiles() {
210 public void dispose() {
215 public void debugPrint(PrintWriter writer
) {
216 synchronized (intervals
) {
217 writer
.println(intervals
.toString());
221 private static Iterator
<ITmfStateInterval
> serachforEndTime(TreeSet
<ITmfStateInterval
> tree
, long time
) {
222 ITmfStateInterval dummyInterval
= new TmfStateInterval(-1, time
, -1, null);
223 ITmfStateInterval myInterval
= tree
.lower(dummyInterval
);
224 if (myInterval
== null) {
225 return tree
.iterator();
227 final SortedSet
<ITmfStateInterval
> tailSet
= tree
.tailSet(myInterval
);
228 Iterator
<ITmfStateInterval
> retVal
= tailSet
.iterator();