1 /*******************************************************************************
2 * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir and others.
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Alexandre Montplaisir - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.segmentstore
.core
.treemap
;
15 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
17 import java
.util
.Collection
;
18 import java
.util
.Iterator
;
19 import java
.util
.TreeMap
;
20 import java
.util
.concurrent
.locks
.ReadWriteLock
;
21 import java
.util
.concurrent
.locks
.ReentrantReadWriteLock
;
23 import org
.eclipse
.jdt
.annotation
.NonNull
;
24 import org
.eclipse
.jdt
.annotation
.Nullable
;
25 import org
.eclipse
.tracecompass
.segmentstore
.core
.ISegment
;
26 import org
.eclipse
.tracecompass
.segmentstore
.core
.ISegmentStore
;
27 import org
.eclipse
.tracecompass
.segmentstore
.core
.SegmentComparators
;
28 import org
.eclipse
.tracecompass
.segmentstore
.core
.SegmentStoreFactory
;
30 import com
.google
.common
.collect
.ImmutableList
;
31 import com
.google
.common
.collect
.Iterables
;
32 import com
.google
.common
.collect
.Ordering
;
33 import com
.google
.common
.collect
.Sets
;
34 import com
.google
.common
.collect
.TreeMultimap
;
37 * Implementation of a {@link ISegmentStore} using in-memory {@link TreeMap}'s.
38 * This relatively simple implementation holds everything in memory, and as such
39 * cannot contain too much data.
41 * The TreeMapStore itself is Iterable, and its iteration order will be by
42 * ascending order of start times. For segments with identical start times, the
43 * secondary comparator will be the end time. If even those are equal, it will
44 * defer to the segments' natural ordering ({@link ISegment#compareTo}).
46 * The store's tree maps will not accept duplicate key-value pairs, which means
47 * that if you want several segments with the same start and end times, make
48 * sure their compareTo() differentiates them.
50 * Removal operations are not supported.
53 * The type of segment held in this store
55 * @author Alexandre Montplaisir
56 * @deprecated Use the {@link SegmentStoreFactory} to create a new segment store
59 public class TreeMapStore
<@NonNull E
extends ISegment
> implements ISegmentStore
<E
> {
61 private final ReadWriteLock fLock
= new ReentrantReadWriteLock(false);
63 private final TreeMultimap
<Long
, E
> fStartTimesIndex
;
64 private final TreeMultimap
<Long
, E
> fEndTimesIndex
;
66 private volatile long fSize
;
68 private @Nullable transient Iterable
<E
> fLastSnapshot
= null;
73 public TreeMapStore() {
75 * For the start times index, the "key comparator" will compare the
76 * start times as longs directly. This is the primary comparator for its
79 * The secondary "value" comparator will check the end times first, and
80 * in the event of a tie, defer to the ISegment's Comparable
81 * implementation, a.k.a. its natural ordering.
83 * The same is done for the end times index, but swapping the first two
84 * comparators instead.
86 fStartTimesIndex
= TreeMultimap
.create(
87 SegmentComparators
.LONG_COMPARATOR
,
88 Ordering
.from(SegmentComparators
.INTERVAL_END_COMPARATOR
).compound(Ordering
.natural()));
90 fEndTimesIndex
= TreeMultimap
.create(
91 SegmentComparators
.LONG_COMPARATOR
,
92 Ordering
.from(SegmentComparators
.INTERVAL_START_COMPARATOR
).compound(Ordering
.natural()));
97 // ------------------------------------------------------------------------
98 // Methods from Collection
99 // ------------------------------------------------------------------------
102 public Iterator
<E
> iterator() {
103 fLock
.readLock().lock();
105 Iterable
<E
> lastSnapshot
= fLastSnapshot
;
106 if (lastSnapshot
== null) {
107 lastSnapshot
= ImmutableList
.copyOf(fStartTimesIndex
.values());
108 fLastSnapshot
= lastSnapshot
;
110 return checkNotNull(lastSnapshot
.iterator());
112 fLock
.readLock().unlock();
117 public boolean add(@Nullable E val
) {
119 throw new IllegalArgumentException();
122 fLock
.writeLock().lock();
124 if (fStartTimesIndex
.put(Long
.valueOf(val
.getStart()), val
)) {
125 fEndTimesIndex
.put(Long
.valueOf(val
.getEnd()), val
);
127 fLastSnapshot
= null;
132 fLock
.writeLock().unlock();
138 return Long
.valueOf(fSize
).intValue();
142 public boolean isEmpty() {
147 public boolean contains(@Nullable Object o
) {
148 fLock
.readLock().lock();
150 return fStartTimesIndex
.containsValue(o
);
152 fLock
.readLock().unlock();
157 public boolean containsAll(@Nullable Collection
<?
> c
) {
158 fLock
.readLock().lock();
160 return fStartTimesIndex
.values().containsAll(c
);
162 fLock
.readLock().unlock();
167 public Object
[] toArray() {
168 fLock
.readLock().lock();
170 return fStartTimesIndex
.values().toArray();
172 fLock
.readLock().unlock();
177 public <T
> T
[] toArray(T
[] a
) {
178 fLock
.readLock().lock();
180 return fStartTimesIndex
.values().toArray(a
);
182 fLock
.readLock().unlock();
187 public boolean remove(@Nullable Object o
) {
188 throw new UnsupportedOperationException();
192 public boolean addAll(@Nullable Collection
<?
extends E
> c
) {
194 throw new IllegalArgumentException();
197 fLock
.writeLock().lock();
199 boolean changed
= false;
201 if (this.add(elem
)) {
207 fLock
.writeLock().unlock();
212 public boolean removeAll(@Nullable Collection
<?
> c
) {
213 throw new UnsupportedOperationException();
217 public boolean retainAll(@Nullable Collection
<?
> c
) {
218 throw new UnsupportedOperationException();
222 public void clear() {
223 fLock
.writeLock().lock();
226 fEndTimesIndex
.clear();
227 fStartTimesIndex
.clear();
229 fLock
.writeLock().unlock();
233 // ------------------------------------------------------------------------
234 // Methods added by ISegmentStore
235 // ------------------------------------------------------------------------
238 public Iterable
<E
> getIntersectingElements(long position
) {
240 * The intervals intersecting 't' are those whose 1) start time is
241 * *lower* than 't' AND 2) end time is *higher* than 't'.
243 fLock
.readLock().lock();
245 Iterable
<E
> matchStarts
= Iterables
.concat(fStartTimesIndex
.asMap().headMap(position
, true).values());
246 Iterable
<E
> matchEnds
= Iterables
.concat(fEndTimesIndex
.asMap().tailMap(position
, true).values());
247 return checkNotNull(Sets
.intersection(Sets
.newHashSet(matchStarts
), Sets
.newHashSet(matchEnds
)));
249 fLock
.readLock().unlock();
254 public Iterable
<E
> getIntersectingElements(long start
, long end
) {
255 fLock
.readLock().lock();
257 Iterable
<E
> matchStarts
= Iterables
.concat(fStartTimesIndex
.asMap().headMap(end
, true).values());
258 Iterable
<E
> matchEnds
= Iterables
.concat(fEndTimesIndex
.asMap().tailMap(start
, true).values());
259 return checkNotNull(Sets
.intersection(Sets
.newHashSet(matchStarts
), Sets
.newHashSet(matchEnds
)));
261 fLock
.readLock().unlock();
266 public void dispose() {
267 fLock
.writeLock().lock();
269 fStartTimesIndex
.clear();
270 fEndTimesIndex
.clear();
273 fLock
.writeLock().unlock();