ss: fix QuarkIterator
Bug 531766
it would catch statesystemdisposedexceptions and throw
NoSuchElementExceptions instead.
Pre-fetching and storing the next and current intervals when
hasNext/Previous is called allows for safer handling of SSDEs
Change-Id: Ic3d79976f484d882972be9e17c03c82762ba7f08
Signed-off-by: Loic Prieur-Drevon <loic.prieurdrevon@gmail.com>
Reviewed-on: https://git.eclipse.org/r/118903
Tested-by: Hudson CI
Reviewed-by: Patrick Tasse <patrick.tasse@gmail.com>
Tested-by: Patrick Tasse <patrick.tasse@gmail.com>
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/cpuusage/CpuUsageDataProvider.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/cpuusage/CpuUsageDataProvider.java
index 0d25bc2..8b29592 100644
--- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/cpuusage/CpuUsageDataProvider.java
+++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/cpuusage/CpuUsageDataProvider.java
@@ -260,7 +260,7 @@
/* Find a name in this attribute's intervals */
Iterator<ITmfStateInterval> iterator = new StateSystemUtils.QuarkIterator(kernelSs, execNameQuark, start);
Iterator<String> names = Iterators.filter(Iterators.transform(iterator, ITmfStateInterval::getValue), String.class);
- if (iterator.hasNext()) {
+ if (names.hasNext()) {
execName = names.next();
fProcessNameMap.put(tid, execName);
return execName;
diff --git a/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/statesystem/core/StateSystemUtils.java b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/statesystem/core/StateSystemUtils.java
index 57c34cd..d6a5eaf 100644
--- a/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/statesystem/core/StateSystemUtils.java
+++ b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/statesystem/core/StateSystemUtils.java
@@ -19,6 +19,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.Objects;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
@@ -297,7 +298,18 @@
private final long fInitialTime;
private final long fEndTime;
+ /**
+ * The last returned interval
+ */
private @Nullable ITmfStateInterval fCurrent;
+ /**
+ * The previous interval (pre-fetched)
+ */
+ private @Nullable ITmfStateInterval fPrevious;
+ /**
+ * The next interval (pre-fetched)
+ */
+ private @Nullable ITmfStateInterval fNext;
/**
* Constructor
@@ -369,6 +381,9 @@
@Override
public boolean hasNext() {
+ if (fNext != null) {
+ return true;
+ }
/*
* Compute the query's real end time here, to update it if the
* iterator is used during state system build
@@ -380,18 +395,26 @@
* query time range. By definition getNextQueryTime() is larger than
* the state system's start time.
*/
- return (getNextQueryTime() <= end);
+ long nextQueryTime = getNextQueryTime();
+ if (nextQueryTime <= end) {
+ try {
+ fNext = fSS.querySingleState(nextQueryTime, fQuark);
+ } catch (StateSystemDisposedException e) {
+ fNext = null;
+ return false;
+ }
+ }
+ return fNext != null;
}
@Override
public ITmfStateInterval next() {
if (hasNext()) {
- try {
- fCurrent = fSS.querySingleState(getNextQueryTime(), fQuark);
- return fCurrent;
- } catch (StateSystemDisposedException e) {
- /* GOTO throw NoSuchElementException. */
- }
+ ITmfStateInterval next = Objects.requireNonNull(fNext, "Inconsistent state, should be non null if hasNext returned true"); //$NON-NLS-1$
+ fPrevious = fCurrent;
+ fCurrent = next;
+ fNext = null;
+ return next;
}
throw new NoSuchElementException();
}
@@ -404,12 +427,24 @@
* @return true if the iteration has more previous elements
*/
public boolean hasPrevious() {
+ if (fPrevious != null) {
+ return true;
+ }
/*
* Ensure that the next query time falls within state system and
* query time range. By definition getPreviousQueryTime() is smaller
* than the state system's end time.
*/
- return (getPreviousQueryTime() >= fSS.getStartTime());
+ long previousQueryTime = getPreviousQueryTime();
+ if (previousQueryTime >= fSS.getStartTime()) {
+ try {
+ fPrevious = fSS.querySingleState(previousQueryTime, fQuark);
+ } catch (StateSystemDisposedException e) {
+ fPrevious = null;
+ return false;
+ }
+ }
+ return fPrevious != null;
}
/**
@@ -419,12 +454,11 @@
*/
public ITmfStateInterval previous() {
if (hasPrevious()) {
- try {
- fCurrent = fSS.querySingleState(getPreviousQueryTime(), fQuark);
- return fCurrent;
- } catch (StateSystemDisposedException e) {
- /* GOTO throw NoSuchElementException. */
- }
+ ITmfStateInterval prev = Objects.requireNonNull(fPrevious, "Inconsistent state, should be non null if hasPrevious returned true"); //$NON-NLS-1$
+ fNext = fCurrent;
+ fCurrent = prev;
+ fPrevious = null;
+ return prev;
}
throw new NoSuchElementException();
}