statesystem: Extract HistoryTreeBackend{Iterator}

Extract an HistoryTreeBackendIterator class from the previous, anonymous
class implementation. Enable the use of IDE breakpoints within e.g.
(now HistoryTreeBackendIterator's) hasNext, this way, for manual or test
debugging purposes.

Pave the way for potentially adding finer log trace events that way too,
for e.g. tracing performance troubleshooting. However preserve the
previous implementation to the letter for this change scope, beside the
necessary yet trivial anonymity undoings.

Reuse the HistoryTreeBackend file header and history lines as is for
this HistoryTreeBackendIterator, but add a line about this specific
change of having extracted the latter. Also add 2022 as this very year.

[Added] HistoryTreeBackendIterator as extracted from HistoryTreeBackend

Change-Id: I741c6c46db4b2e80ae1fcc4545a17097bfd23dc0
Signed-off-by: Marco Miller <marco.miller@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/194434
Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org>
Tested-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
Tested-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Reviewed-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
diff --git a/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/backend/historytree/HistoryTreeBackend.java b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/backend/historytree/HistoryTreeBackend.java
index 5e2ec09..ff30e88 100644
--- a/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/backend/historytree/HistoryTreeBackend.java
+++ b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/backend/historytree/HistoryTreeBackend.java
@@ -22,9 +22,7 @@
 import java.io.IOException;
 import java.nio.channels.ClosedChannelException;
 import java.util.ArrayDeque;
-import java.util.Collections;
 import java.util.Deque;
-import java.util.Iterator;
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -361,51 +359,7 @@
                 "ssid", getSSID(), //$NON-NLS-1$
                 "quarks", quarks, //$NON-NLS-1$
                 "timeCondition", times).build()) { //$NON-NLS-1$
-            return () -> new Iterator<@NonNull ITmfStateInterval>() {
-                private final Deque<Integer> seqNumberQueue = new ArrayDeque<>(Collections.singleton(getSHT().getRootNode().getSequenceNumber()));
-                private Iterator<@NonNull HTInterval> intervalQueue = Collections.emptyIterator();
-
-                @Override
-                public boolean hasNext() {
-                    while (!intervalQueue.hasNext() && !seqNumberQueue.isEmpty()) {
-                        try {
-                            HTNode currentNode = getSHT().readNode(seqNumberQueue);
-                            /*
-                             * Compute reduced conditions here to reduce complexity in queuing operations.
-                             */
-                            TimeRangeCondition subTimes = times.subCondition(currentNode.getNodeStart(), currentNode.getNodeEnd());
-                            /*
-                             * During the SHT construction, the bounds of the children are not final, so we
-                             * may have queued some nodes which don't overlap the query.
-                             */
-                            if (quarks.intersects(currentNode.getMinQuark(), currentNode.getMaxQuark()) && subTimes != null) {
-                                if (currentNode.getNodeType() == HTNode.NodeType.CORE) {
-                                    // Queue the relevant children nodes for BFS.
-                                    ((ParentNode) currentNode).queueNextChildren2D(quarks, subTimes, seqNumberQueue, reverse);
-                                }
-                                intervalQueue = currentNode.iterable2D(quarks, subTimes).iterator();
-                            }
-                        } catch (ClosedChannelException e) {
-                            try (TraceCompassLogUtils.FlowScopeLog closedChannelLog = new TraceCompassLogUtils.FlowScopeLogBuilder(LOGGER, Level.FINER,
-                                    "HistoryTreeBackend:query2D:channelClosed").setParentScope(log).build()) { //$NON-NLS-1$
-                                return false;
-                            }
-                        }
-                    }
-                    boolean hasNext = intervalQueue.hasNext();
-                    if (!hasNext) {
-                        try (TraceCompassLogUtils.FlowScopeLog noNext = new TraceCompassLogUtils.FlowScopeLogBuilder(LOGGER, Level.FINER,
-                                "HistoryTreeBackend:query2D:iteratorEnd").setParentScope(log).build()) { //$NON-NLS-1$
-                        }
-                    }
-                    return intervalQueue.hasNext();
-                }
-
-                @Override
-                public ITmfStateInterval next() {
-                    return intervalQueue.next();
-                }
-            };
+            return () -> new HistoryTreeBackendIterator(getSHT(), quarks, times, reverse, log);
         }
     }
 
diff --git a/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/backend/historytree/HistoryTreeBackendIterator.java b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/backend/historytree/HistoryTreeBackendIterator.java
new file mode 100644
index 0000000..f409b81
--- /dev/null
+++ b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/backend/historytree/HistoryTreeBackendIterator.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2016, 2022 Ericsson
+ * Copyright (c) 2010, 2011 École Polytechnique de Montréal
+ * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License 2.0 which
+ * accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *   Alexandre Montplaisir - Initial API and implementation
+ *   Patrick Tasse - Add message to exceptions
+ *   Marco Miller - Extract to this class
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.statesystem.core.backend.historytree;
+
+import java.nio.channels.ClosedChannelException;
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.tracecompass.common.core.log.TraceCompassLog;
+import org.eclipse.tracecompass.common.core.log.TraceCompassLogUtils;
+import org.eclipse.tracecompass.internal.provisional.datastore.core.condition.IntegerRangeCondition;
+import org.eclipse.tracecompass.internal.provisional.datastore.core.condition.TimeRangeCondition;
+import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
+
+class HistoryTreeBackendIterator implements Iterator<@NonNull ITmfStateInterval> {
+    private static final @NonNull Logger LOGGER = TraceCompassLog.getLogger(HistoryTreeBackendIterator.class);
+
+    private final @NonNull IHistoryTree fSht;
+    private final IntegerRangeCondition fQuarks;
+    private final TimeRangeCondition fTimes;
+    private final boolean fReverse;
+    private final TraceCompassLogUtils.@NonNull FlowScopeLog fParentLog;
+    private final Deque<Integer> fSeqNumberQueue;
+
+    private Iterator<@NonNull HTInterval> intervalQueue = Collections.emptyIterator();
+
+    HistoryTreeBackendIterator(@NonNull IHistoryTree sht, IntegerRangeCondition quarks, TimeRangeCondition times, boolean reverse, TraceCompassLogUtils.@NonNull FlowScopeLog parentLog) {
+        fSht = sht;
+        fQuarks = quarks;
+        fTimes = times;
+        fReverse = reverse;
+        fParentLog = parentLog;
+        fSeqNumberQueue = new ArrayDeque<>(Collections.singleton(fSht.getRootNode().getSequenceNumber()));
+    }
+
+    @Override
+    public boolean hasNext() {
+        while (!intervalQueue.hasNext() && !fSeqNumberQueue.isEmpty()) {
+            try {
+                HTNode currentNode = fSht.readNode(fSeqNumberQueue);
+                /*
+                 * Compute reduced conditions here to reduce complexity in
+                 * queuing operations.
+                 */
+                TimeRangeCondition subTimes = fTimes.subCondition(currentNode.getNodeStart(), currentNode.getNodeEnd());
+                /*
+                 * During the SHT construction, the bounds of the children are
+                 * not final, so we may have queued some nodes which don't
+                 * overlap the query.
+                 */
+                if (fQuarks.intersects(currentNode.getMinQuark(), currentNode.getMaxQuark()) && subTimes != null) {
+                    if (currentNode.getNodeType() == HTNode.NodeType.CORE) {
+                        // Queue the relevant children nodes for BFS.
+                        ((ParentNode) currentNode).queueNextChildren2D(fQuarks, subTimes, fSeqNumberQueue, fReverse);
+                    }
+                    intervalQueue = currentNode.iterable2D(fQuarks, subTimes).iterator();
+                }
+            } catch (ClosedChannelException e) {
+                try (TraceCompassLogUtils.FlowScopeLog closedChannelLog = new TraceCompassLogUtils.FlowScopeLogBuilder(LOGGER, Level.FINER,
+                        "HistoryTreeBackendIterator:query2D:channelClosed").setParentScope(fParentLog).build()) { //$NON-NLS-1$
+                    return false;
+                }
+            }
+        }
+        boolean hasNext = intervalQueue.hasNext();
+        if (!hasNext) {
+            try (TraceCompassLogUtils.FlowScopeLog noNext = new TraceCompassLogUtils.FlowScopeLogBuilder(LOGGER, Level.FINER,
+                    "HistoryTreeBackendIterator:query2D:iteratorEnd").setParentScope(fParentLog).build()) { //$NON-NLS-1$
+            }
+        }
+        return intervalQueue.hasNext();
+    }
+
+    @Override
+    public ITmfStateInterval next() {
+        return intervalQueue.next();
+    }
+}