import java.util.List;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
public Iterable<E> getIntersectingElements(long start, long end) {
fLock.readLock().lock();
try {
- int index = Collections.binarySearch(fStore, new BasicSegment(end, Long.MAX_VALUE));
- index = (index >= 0) ? index : -index - 1;
- return fStore.subList(0, index).stream().filter(element -> !(start > element.getEnd() || end < element.getStart())).collect(Collectors.toList());
+ /*
+ * Compute the index of the last Segment we will find in here,
+ * correct the negative insertion point and add 1 for array size.
+ */
+ int arraySize = Collections.binarySearch(fStore, new BasicSegment(end, Long.MAX_VALUE));
+ arraySize = (arraySize >= 0) ? arraySize + 1 : -arraySize;
+ /*
+ * Create the ArrayList as late as possible, with size = (first
+ * intersecting segment index) - (last intersecting segment index).
+ */
+ ArrayList<E> iterable = null;
+ for (E seg : fStore) {
+ if (seg.getStart() <= end && seg.getEnd() >= start) {
+ if (iterable == null) {
+ iterable = new ArrayList<>(arraySize);
+ }
+ iterable.add(seg);
+ } else if (seg.getStart() > end) {
+ /*
+ * Since segments are sorted by start times, there is no
+ * point in searching segments that start too late.
+ */
+ break;
+ }
+ arraySize--;
+ }
+ if (iterable != null) {
+ iterable.trimToSize();
+ return iterable;
+ }
+ return Collections.EMPTY_LIST;
} finally {
fLock.readLock().unlock();
}
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
private @Nullable transient Iterable<E> fLastSnapshot = null;
private volatile boolean fDirty = false;
+ private volatile long fStart = Long.MAX_VALUE;
+ private volatile long fEnd = Long.MIN_VALUE;
/**
* Constructor
E element = (E) array[i];
setDirtyIfNeeded(element);
fStore.add(element);
+ fStart = Math.min(fStart, element.getStart());
+ fEnd = Math.max(fEnd, element.getEnd());
}
}
if (fDirty) {
setDirtyIfNeeded(val);
fStore.add(val);
fLastSnapshot = null;
+ fStart = Math.min(fStart, val.getStart());
+ fEnd = Math.max(fEnd, val.getEnd());
return true;
} finally {
fLock.unlock();
sortStore();
}
try {
- int index = Collections.binarySearch(fStore, new BasicSegment(end, Long.MAX_VALUE));
- index = (index >= 0) ? index : -index - 1;
- return fStore.subList(0, index).stream().filter(element -> !(start > element.getEnd() || end < element.getStart())).collect(Collectors.toList());
+ if (start <= fStart && end >= fEnd) {
+ Iterable<E> lastSnapshot = fLastSnapshot;
+ if (lastSnapshot == null) {
+ lastSnapshot = ImmutableList.copyOf(fStore);
+ fLastSnapshot = lastSnapshot;
+ }
+ return checkNotNull(lastSnapshot);
+ }
+ /*
+ * Compute the index of the last Segment we will find in here,
+ * correct the negative insertion point and add 1 for array size.
+ */
+ int arraySize = Collections.binarySearch(fStore, new BasicSegment(end, Long.MAX_VALUE));
+ arraySize = (arraySize >= 0) ? arraySize + 1 : -arraySize;
+ /*
+ * Create the ArrayList as late as possible, with size = (first
+ * intersecting segment index) - (last intersecting segment index).
+ */
+ ArrayList<E> iterable = null;
+ for (E seg : fStore) {
+ if (seg.getStart() <= end && seg.getEnd() >= start) {
+ if (iterable == null) {
+ iterable = new ArrayList<>(arraySize);
+ }
+ iterable.add(seg);
+ } else if (seg.getStart() > end) {
+ /*
+ * Since segments are sorted by start times, there is no
+ * point in searching segments that start too late.
+ */
+ break;
+ }
+ arraySize--;
+ }
+ if (iterable != null) {
+ iterable.trimToSize();
+ return iterable;
+ }
+ return Collections.EMPTY_LIST;
} finally {
fLock.unlock();
}
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Comparator;
import java.util.Iterator;
-import java.util.TreeMap;
+import java.util.List;
+import java.util.NavigableSet;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Function;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.segmentstore.core.BasicSegment;
import org.eclipse.tracecompass.segmentstore.core.ISegment;
import org.eclipse.tracecompass.segmentstore.core.ISegmentStore;
-import org.eclipse.tracecompass.segmentstore.core.SegmentComparators;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Ordering;
-import com.google.common.collect.Sets;
import com.google.common.collect.TreeMultimap;
/**
- * Implementation of a {@link ISegmentStore} using in-memory {@link TreeMap}'s.
+ * Implementation of a {@link ISegmentStore} using an in-memory {@link TreeMultimap}s.
* This relatively simple implementation holds everything in memory, and as such
* cannot contain too much data.
*
* secondary comparator will be the end time. If even those are equal, it will
* defer to the segments' natural ordering ({@link ISegment#compareTo}).
*
- * The store's tree maps will not accept duplicate key-value pairs, which means
+ * The store's tree map will not accept duplicate key-value pairs, which means
* that if you want several segments with the same start and end times, make
* sure their compareTo() differentiates them.
*
private final ReadWriteLock fLock = new ReentrantReadWriteLock(false);
private final TreeMultimap<Long, E> fStartTimesIndex;
- private final TreeMultimap<Long, E> fEndTimesIndex;
- private volatile long fSize;
+ private volatile int fSize;
+ private volatile long fStart = Long.MAX_VALUE;
+ private volatile long fEnd = Long.MIN_VALUE;
private @Nullable transient Iterable<E> fLastSnapshot = null;
* The secondary "value" comparator will check the end times first, and
* in the event of a tie, defer to the ISegment's Comparable
* implementation, a.k.a. its natural ordering.
- *
- * The same is done for the end times index, but swapping the first two
- * comparators instead.
*/
- fStartTimesIndex = TreeMultimap.create(
- SegmentComparators.LONG_COMPARATOR,
- Ordering.from(SegmentComparators.INTERVAL_END_COMPARATOR).compound(Ordering.natural()));
-
- fEndTimesIndex = TreeMultimap.create(
- SegmentComparators.LONG_COMPARATOR,
- Ordering.from(SegmentComparators.INTERVAL_START_COMPARATOR).compound(Ordering.natural()));
+ fStartTimesIndex = TreeMultimap.create(Comparator.<Long>naturalOrder(),
+ Comparator.comparingLong(E::getEnd).thenComparing(Function.identity()));
fSize = 0;
}
fLock.writeLock().lock();
try {
- if (fStartTimesIndex.put(Long.valueOf(val.getStart()), val)) {
- fEndTimesIndex.put(Long.valueOf(val.getEnd()), val);
+ boolean put = fStartTimesIndex.put(val.getStart(), val);
+ if (put) {
fSize++;
+ fStart = Math.min(fStart, val.getStart());
+ fEnd = Math.max(fEnd, val.getEnd());
fLastSnapshot = null;
- return true;
}
- return false;
+ return put;
} finally {
fLock.writeLock().unlock();
}
@Override
public int size() {
- return Long.valueOf(fSize).intValue();
+ return fSize;
}
@Override
@Override
public boolean contains(@Nullable Object o) {
+ if (o == null || !(o instanceof ISegment)) {
+ return false;
+ }
fLock.readLock().lock();
try {
- return fStartTimesIndex.containsValue(o);
+ /* Narrow down the search */
+ ISegment seg = (ISegment) o;
+ return fStartTimesIndex.get(seg.getStart()).contains(o);
} finally {
fLock.readLock().unlock();
}
try {
boolean changed = false;
for (E elem : c) {
- if (this.add(elem)) {
+ if (add(elem)) {
changed = true;
}
}
fLock.writeLock().lock();
try {
fSize = 0;
- fEndTimesIndex.clear();
+ fStart = Long.MAX_VALUE;
+ fEnd = Long.MIN_VALUE;
fStartTimesIndex.clear();
} finally {
fLock.writeLock().unlock();
public Iterable<E> getIntersectingElements(long start, long end) {
fLock.readLock().lock();
try {
- Iterable<E> matchStarts = Iterables.concat(fStartTimesIndex.asMap().headMap(end, true).values());
- Iterable<E> matchEnds = Iterables.concat(fEndTimesIndex.asMap().tailMap(start, true).values());
- return checkNotNull(Sets.intersection(Sets.newHashSet(matchStarts), Sets.newHashSet(matchEnds)));
+ if (start <= fStart && end >= fEnd) {
+ if (fLastSnapshot == null) {
+ fLastSnapshot = ImmutableList.copyOf(fStartTimesIndex.values());
+ }
+ return checkNotNull(fLastSnapshot);
+ }
+ List<E> iterable = new ArrayList<>();
+ /**
+ * fromElement is used to search the navigable sets of the
+ * TreeMultiMap for Segments that end after start query time.
+ */
+ E fromElement = (E) new BasicSegment(Long.MIN_VALUE, start);
+ /* Get the sets of segments for startTimes <= end */
+ for (Collection<E> col : fStartTimesIndex.asMap().headMap(end, true).values()) {
+ /*
+ * The collections of segments are NavigableSets for
+ * TreeMultimap, add elements from the tailSet: which will have
+ * endTimes >= start.
+ */
+ NavigableSet<E> nav = (NavigableSet<E>) col;
+ iterable.addAll(nav.tailSet(fromElement, true));
+ }
+ return iterable;
} finally {
fLock.readLock().unlock();
}
@Override
public void dispose() {
- fLock.writeLock().lock();
- try {
- fStartTimesIndex.clear();
- fEndTimesIndex.clear();
- fSize = 0;
- } finally {
- fLock.writeLock().unlock();
- }
+ clear();
}
}
package org.eclipse.tracecompass.segmentstore.core;
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.Comparator;
-import java.util.Iterator;
import java.util.List;
-import org.eclipse.jdt.annotation.NonNull;
-
import com.google.common.collect.Lists;
import org.eclipse.jdt.annotation.Nullable;
* @return The intervals that cross this position
* @since 1.1
*/
- default Iterable<E> getIntersectingElements(long start, long end, Comparator<ISegment> order){
- List<E> list = Lists.newArrayList(getIntersectingElements(start, end));
- return new Iterable<@NonNull E>() {
- @Override
- public Iterator<@NonNull E> iterator() {
- Collections.sort(list, order);
- return list.iterator();
- }
- };
+ default Iterable<E> getIntersectingElements(long start, long end, Comparator<ISegment> order) {
+ Iterable<E> ret = getIntersectingElements(start, end);
+ List<E> list;
+ if (ret instanceof ArrayList<?>) {
+ /*
+ * No point in copying the intersecting elements into a new
+ * ArrayList if they are already in a new ArrayList.
+ */
+ list = (List<E>) ret;
+ } else {
+ list = Lists.newArrayList(ret);
+ }
+ list.sort(order);
+ return list;
}
/**