From 1a9cb076d18071a3f6aba14d07806df070066ccd Mon Sep 17 00:00:00 2001 From: Alexandre Montplaisir Date: Thu, 24 Sep 2015 17:55:23 -0400 Subject: [PATCH] ss: Make ISegmentStore implement Collection It used to implement Iterable, not many changes are required to support the entirety of Collection. Change-Id: I1622c222d3eb72afdde47ca0a462003dda85d0cd Signed-off-by: Alexandre Montplaisir Reviewed-on: https://git.eclipse.org/r/56680 Reviewed-by: Hudson CI Reviewed-by: Matthew Khouzam Tested-by: Matthew Khouzam --- .../linux/core/latency/LatencyAnalysis.java | 2 +- .../core/tests/treemap/TreeMapStoreTest.java | 71 +++++++-- .../segmentstore/core/ISegmentStore.java | 24 +-- .../core/treemap/TreeMapStore.java | 140 +++++++++++++++--- 4 files changed, 190 insertions(+), 47 deletions(-) diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/latency/LatencyAnalysis.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/latency/LatencyAnalysis.java index 8b8d50f6d0..7aaf4396d0 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/latency/LatencyAnalysis.java +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/latency/LatencyAnalysis.java @@ -202,7 +202,7 @@ public class LatencyAnalysis extends TmfAbstractAnalysisModule { long endTime = event.getTimestamp().getValue(); int ret = ((Long) event.getContent().getField("ret").getValue()).intValue(); //$NON-NLS-1$ ISegment syscall = new SystemCall(info, endTime, ret); - fFullSyscalls.addElement(syscall); + fFullSyscalls.add(syscall); } } diff --git a/statesystem/org.eclipse.tracecompass.segmentstore.core.tests/src/org/eclipse/tracecompass/segmentstore/core/tests/treemap/TreeMapStoreTest.java b/statesystem/org.eclipse.tracecompass.segmentstore.core.tests/src/org/eclipse/tracecompass/segmentstore/core/tests/treemap/TreeMapStoreTest.java index f9f112133b..ecd7629fef 100644 --- a/statesystem/org.eclipse.tracecompass.segmentstore.core.tests/src/org/eclipse/tracecompass/segmentstore/core/tests/treemap/TreeMapStoreTest.java +++ b/statesystem/org.eclipse.tracecompass.segmentstore.core.tests/src/org/eclipse/tracecompass/segmentstore/core/tests/treemap/TreeMapStoreTest.java @@ -11,7 +11,10 @@ package org.eclipse.tracecompass.segmentstore.core.tests.treemap; import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import java.util.Arrays; import java.util.List; import org.eclipse.tracecompass.segmentstore.core.BasicSegment; @@ -50,7 +53,7 @@ public class TreeMapStoreTest { public void setup() { fSegmentStore = new TreeMapStore<>(); for (ISegment segment : SEGMENTS) { - fSegmentStore.addElement(checkNotNull(segment)); + fSegmentStore.add(checkNotNull(segment)); } } @@ -63,11 +66,61 @@ public class TreeMapStoreTest { } /** - * Testing method getNbElements + * Testing method size() */ @Test - public void testGetNbElements() { - assertEquals(SEGMENTS.size(), fSegmentStore.getNbElements()); + public void testSize() { + assertEquals(SEGMENTS.size(), fSegmentStore.size()); + } + + /** + * Test the contains() method. + */ + @Test + public void testContains() { + ISegment otherSegment = new BasicSegment(0, 20); + + assertTrue(fSegmentStore.contains(SEGMENT_2_6)); + assertTrue(fSegmentStore.contains(SEGMENT_4_8)); + assertFalse(fSegmentStore.contains(otherSegment)); + } + + /** + * Test the toArray() method. + */ + @Test + public void testToObjectArray() { + Object[] array = fSegmentStore.toArray(); + + assertEquals(SEGMENTS.size(), array.length); + assertTrue(Arrays.asList(array).containsAll(SEGMENTS)); + } + + /** + * Test the toArray(T[]) method. + */ + @Test + public void testToSpecificArray() { + ISegment[] array = fSegmentStore.toArray(new ISegment[0]); + + assertEquals(SEGMENTS.size(), array.length); + assertTrue(Arrays.asList(array).containsAll(SEGMENTS)); + } + + /** + * Test the toArray(T[]) method with a subtype of ISegment. + */ + @Test + public void testToSpecifyArraySubtype() { + TreeMapStore tms2 = new TreeMapStore<>(); + BasicSegment otherSegment = new BasicSegment(2, 6); + tms2.add(otherSegment); + BasicSegment[] array = tms2.toArray(new BasicSegment[0]); + + assertEquals(1, array.length); + assertTrue(Arrays.asList(array).contains(otherSegment)); + + tms2.dispose(); } /** @@ -76,9 +129,9 @@ public class TreeMapStoreTest { @Test public void testNoDuplicateElements() { for (ISegment segment : SEGMENTS) { - fSegmentStore.addElement(new BasicSegment(segment.getStart(), segment.getEnd())); + fSegmentStore.add(new BasicSegment(segment.getStart(), segment.getEnd())); } - assertEquals(SEGMENTS.size(), fSegmentStore.getNbElements()); + assertEquals(SEGMENTS.size(), fSegmentStore.size()); } /** @@ -101,7 +154,7 @@ public class TreeMapStoreTest { /* Prepare the segment store, we don't use the 'fixture' in this test */ TreeMapStore store = new TreeMapStore<>(); for (ISegment segment : REVERSE_SEGMENTS) { - store.addElement(checkNotNull(segment)); + store.add(checkNotNull(segment)); } /* @@ -238,8 +291,8 @@ public class TreeMapStoreTest { @Test public void testDispose() { TreeMapStore store = new TreeMapStore<>(); - store.addElement(checkNotNull(SEGMENT_2_6)); + store.add(SEGMENT_2_6); store.dispose(); - assertEquals(0, store.getNbElements()); + assertEquals(0, store.size()); } } \ No newline at end of file diff --git a/statesystem/org.eclipse.tracecompass.segmentstore.core/src/org/eclipse/tracecompass/segmentstore/core/ISegmentStore.java b/statesystem/org.eclipse.tracecompass.segmentstore.core/src/org/eclipse/tracecompass/segmentstore/core/ISegmentStore.java index 41af51d144..774dac2833 100644 --- a/statesystem/org.eclipse.tracecompass.segmentstore.core/src/org/eclipse/tracecompass/segmentstore/core/ISegmentStore.java +++ b/statesystem/org.eclipse.tracecompass.segmentstore.core/src/org/eclipse/tracecompass/segmentstore/core/ISegmentStore.java @@ -12,30 +12,18 @@ package org.eclipse.tracecompass.segmentstore.core; +import java.util.Collection; + /** * Interface for segment-storing backends. * - * @param + * @param * The type of {@link ISegment} element that will be stored in this * database. * * @author Alexandre Montplaisir */ -public interface ISegmentStore extends Iterable { - - /** - * Add an element to the database. - * - * @param elem The element to add. - */ - void addElement(T elem); - - /** - * Get the number of element currently existing in the database. - * - * @return The number of elements. - */ - long getNbElements(); +public interface ISegmentStore extends Collection { /** * Retrieve all elements that inclusively cross the given position. @@ -45,7 +33,7 @@ public interface ISegmentStore extends Iterable { * tree's X axis represents time. * @return The intervals that cross this position */ - Iterable getIntersectingElements(long position); + Iterable getIntersectingElements(long position); /** * Retrieve all elements that inclusively cross another segment. We define @@ -64,7 +52,7 @@ public interface ISegmentStore extends Iterable { * The target end position * @return The elements overlapping with this segment */ - Iterable getIntersectingElements(long start, long end); + Iterable getIntersectingElements(long start, long end); /** * Dispose the data structure and release any system resources associated diff --git a/statesystem/org.eclipse.tracecompass.segmentstore.core/src/org/eclipse/tracecompass/segmentstore/core/treemap/TreeMapStore.java b/statesystem/org.eclipse.tracecompass.segmentstore.core/src/org/eclipse/tracecompass/segmentstore/core/treemap/TreeMapStore.java index 81f37a0306..1632d91c04 100644 --- a/statesystem/org.eclipse.tracecompass.segmentstore.core/src/org/eclipse/tracecompass/segmentstore/core/treemap/TreeMapStore.java +++ b/statesystem/org.eclipse.tracecompass.segmentstore.core/src/org/eclipse/tracecompass/segmentstore/core/treemap/TreeMapStore.java @@ -14,6 +14,7 @@ package org.eclipse.tracecompass.segmentstore.core.treemap; import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; +import java.util.Collection; import java.util.Iterator; import java.util.TreeMap; import java.util.concurrent.locks.ReadWriteLock; @@ -44,21 +45,23 @@ import com.google.common.collect.TreeMultimap; * that if you want several segments with the same start and end times, make * sure their compareTo() differentiates them. * - * @param + * Removal operations are not supported. + * + * @param * The type of segment held in this store * * @author Alexandre Montplaisir */ -public class TreeMapStore implements ISegmentStore { +public class TreeMapStore implements ISegmentStore { private final ReadWriteLock fLock = new ReentrantReadWriteLock(false); - private final TreeMultimap fStartTimesIndex; - private final TreeMultimap fEndTimesIndex; + private final TreeMultimap fStartTimesIndex; + private final TreeMultimap fEndTimesIndex; - private long fSize; + private volatile long fSize; - private @Nullable transient Iterable fLastSnapshot = null; + private @Nullable transient Iterable fLastSnapshot = null; /** * Constructor @@ -76,22 +79,26 @@ public class TreeMapStore implements ISegmentStore { * The same is done for the end times index, but swapping the first two * comparators instead. */ - fStartTimesIndex = checkNotNull(TreeMultimap. create( + fStartTimesIndex = checkNotNull(TreeMultimap. create( SegmentComparators.LONG_COMPARATOR, Ordering.from(SegmentComparators.INTERVAL_END_COMPARATOR).compound(Ordering.natural()))); - fEndTimesIndex = checkNotNull(TreeMultimap. create( + fEndTimesIndex = checkNotNull(TreeMultimap. create( SegmentComparators.LONG_COMPARATOR, Ordering.from(SegmentComparators.INTERVAL_START_COMPARATOR).compound(Ordering.natural()))); fSize = 0; } + // ------------------------------------------------------------------------ + // Methods from Collection + // ------------------------------------------------------------------------ + @Override - public Iterator iterator() { + public Iterator iterator() { fLock.readLock().lock(); try { - Iterable lastSnapshot = fLastSnapshot; + Iterable lastSnapshot = fLastSnapshot; if (lastSnapshot == null) { lastSnapshot = checkNotNull(ImmutableList.copyOf(fStartTimesIndex.values())); fLastSnapshot = lastSnapshot; @@ -103,9 +110,18 @@ public class TreeMapStore implements ISegmentStore { } @Override - public void addElement(T val) { + public boolean add(@Nullable E val) { + if (val == null) { + throw new IllegalArgumentException(); + } + fLock.writeLock().lock(); try { + /* We can take a read lock while holding the write lock. */ + if (contains(val)) { + return false; + } + if (fStartTimesIndex.put(Long.valueOf(val.getStart()), val)) { fEndTimesIndex.put(Long.valueOf(val.getEnd()), val); fSize++; @@ -114,28 +130,114 @@ public class TreeMapStore implements ISegmentStore { } finally { fLock.writeLock().unlock(); } + return true; + } + + @Override + public int size() { + return Long.valueOf(fSize).intValue(); + } + + @Override + public boolean isEmpty() { + return (fSize == 0); } @Override - public long getNbElements() { + public boolean contains(@Nullable Object o) { fLock.readLock().lock(); try { - return fSize; + return fStartTimesIndex.containsValue(o); } finally { fLock.readLock().unlock(); } } + + @Override + public boolean containsAll(@Nullable Collection c) { + fLock.readLock().lock(); + try { + return fStartTimesIndex.values().containsAll(c); + } finally { + fLock.readLock().unlock(); + } + } + + @Override + public Object[] toArray() { + fLock.readLock().lock(); + try { + return checkNotNull(fStartTimesIndex.values().toArray()); + } finally { + fLock.readLock().unlock(); + } + } + + @Override + public T[] toArray(@Nullable T[] a) { + fLock.readLock().lock(); + try { + return checkNotNull(fStartTimesIndex.values().toArray(a)); + } finally { + fLock.readLock().unlock(); + } + } + + @Override + public boolean remove(@Nullable Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(@Nullable Collection c) { + if (c == null) { + throw new IllegalArgumentException(); + } + + fLock.writeLock().lock(); + try { + boolean changed = false; + for (E elem : c) { + if (this.add(elem)) { + changed = true; + } + } + return changed; + } finally { + fLock.writeLock().unlock(); + } + } + + @Override + public boolean removeAll(@Nullable Collection c) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(@Nullable Collection c) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + // ------------------------------------------------------------------------ + // Methods added by ISegmentStore + // ------------------------------------------------------------------------ + @Override - public Iterable getIntersectingElements(long position) { + public Iterable getIntersectingElements(long position) { /* * The intervals intersecting 't' are those whose 1) start time is * *lower* than 't' AND 2) end time is *higher* than 't'. */ fLock.readLock().lock(); try { - Iterable matchStarts = Iterables.concat(fStartTimesIndex.asMap().headMap(position, true).values()); - Iterable matchEnds = Iterables.concat(fEndTimesIndex.asMap().tailMap(position, true).values()); + Iterable matchStarts = Iterables.concat(fStartTimesIndex.asMap().headMap(position, true).values()); + Iterable matchEnds = Iterables.concat(fEndTimesIndex.asMap().tailMap(position, true).values()); return checkNotNull(Sets.intersection(Sets.newHashSet(matchStarts), Sets.newHashSet(matchEnds))); } finally { fLock.readLock().unlock(); @@ -143,11 +245,11 @@ public class TreeMapStore implements ISegmentStore { } @Override - public Iterable getIntersectingElements(long start, long end) { + public Iterable getIntersectingElements(long start, long end) { fLock.readLock().lock(); try { - Iterable matchStarts = Iterables.concat(fStartTimesIndex.asMap().headMap(end, true).values()); - Iterable matchEnds = Iterables.concat(fEndTimesIndex.asMap().tailMap(start, true).values()); + Iterable matchStarts = Iterables.concat(fStartTimesIndex.asMap().headMap(end, true).values()); + Iterable matchEnds = Iterables.concat(fEndTimesIndex.asMap().tailMap(start, true).values()); return checkNotNull(Sets.intersection(Sets.newHashSet(matchStarts), Sets.newHashSet(matchEnds))); } finally { fLock.readLock().unlock(); -- 2.34.1