Merge remote-tracking branch 'origin/fluo-425'
diff --git a/docs/applications.md b/docs/applications.md
index 7471a3d..5685381 100644
--- a/docs/applications.md
+++ b/docs/applications.md
@@ -143,9 +143,10 @@
| Logger | Level | Information |
|----------------------|-------|----------------------------------------------------------------------------------------------------|
-| `fluo.tx` | TRACE | Provides detailed information about what transactions read and wrote |
-| `fluo.tx.summary` | TRACE | Provides a one line summary about each transaction executed |
-| `fluo.tx.collisions` | TRACE | Provides details about what data was involved When a transaction collides with another transaction |
+| fluo.tx | TRACE | Provides detailed information about what transactions read and wrote |
+| fluo.tx.summary | TRACE | Provides a one line summary about each transaction executed |
+| fluo.tx.collisions | TRACE | Provides details about what data was involved When a transaction collides with another transaction |
+| fluo.tx.scan | TRACE | Provides logging for each cell read by a scan. Scan summary logged at `fluo.tx` level. This allows suppression of `fluo.tx.scan` while still seeing summary. |
Below is an example log after setting `fluo.tx` to TRACE. The number following `txid: ` is the
transactions start timestamp from the Oracle.
diff --git a/modules/api/src/main/java/org/apache/fluo/api/config/SimpleConfiguration.java b/modules/api/src/main/java/org/apache/fluo/api/config/SimpleConfiguration.java
index a92dc1d..9877b18 100644
--- a/modules/api/src/main/java/org/apache/fluo/api/config/SimpleConfiguration.java
+++ b/modules/api/src/main/java/org/apache/fluo/api/config/SimpleConfiguration.java
@@ -18,8 +18,6 @@
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
diff --git a/modules/core/src/main/java/org/apache/fluo/core/log/TracingCellScanner.java b/modules/core/src/main/java/org/apache/fluo/core/log/TracingCellScanner.java
new file mode 100644
index 0000000..9d77315
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/fluo/core/log/TracingCellScanner.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.fluo.core.log;
+
+import java.util.Iterator;
+
+import com.google.common.collect.Iterators;
+import org.apache.fluo.api.client.scanner.CellScanner;
+import org.apache.fluo.api.config.FluoConfiguration;
+import org.apache.fluo.api.data.RowColumnValue;
+import org.apache.fluo.core.util.Hex;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TracingCellScanner implements CellScanner {
+ static final Logger log = LoggerFactory.getLogger(FluoConfiguration.TRANSACTION_PREFIX + ".scan");
+
+ private final CellScanner wrappedScanner;
+ private final long txid;
+ private final String scanId;
+
+ TracingCellScanner(CellScanner wrappedScanner, long txid, String scanId) {
+ this.wrappedScanner = wrappedScanner;
+ this.txid = txid;
+ this.scanId = scanId;
+ }
+
+ @Override
+ public Iterator<RowColumnValue> iterator() {
+ return Iterators.transform(
+ wrappedScanner.iterator(),
+ rcv -> {
+ log.trace("txid: {} scanId: {} next()-> {} {}", txid, scanId,
+ Hex.encNonAscii(rcv.getRowColumn()), Hex.encNonAscii(rcv.getValue()));
+ return rcv;
+ });
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/fluo/core/log/TracingColumnScanner.java b/modules/core/src/main/java/org/apache/fluo/core/log/TracingColumnScanner.java
new file mode 100644
index 0000000..d950a80
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/fluo/core/log/TracingColumnScanner.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.fluo.core.log;
+
+import java.util.Iterator;
+
+import com.google.common.collect.Iterators;
+import org.apache.fluo.api.client.scanner.ColumnScanner;
+import org.apache.fluo.api.data.Bytes;
+import org.apache.fluo.api.data.ColumnValue;
+import org.apache.fluo.core.util.Hex;
+import org.slf4j.Logger;
+
+public class TracingColumnScanner implements ColumnScanner {
+
+ static final Logger log = TracingCellScanner.log;
+
+ private final ColumnScanner cs;
+ private final long txid;
+ private final String scanId;
+ private final String encRow;
+
+ TracingColumnScanner(ColumnScanner cs, long txid, String scanId) {
+ this.cs = cs;
+ this.txid = txid;
+ this.scanId = scanId;
+ this.encRow = Hex.encNonAscii(cs.getRow());
+ }
+
+ @Override
+ public Iterator<ColumnValue> iterator() {
+ return Iterators.transform(
+ cs.iterator(),
+ cv -> {
+ log.trace("txid: {} scanId: {} next()-> {} {} {}", txid, scanId, encRow,
+ Hex.encNonAscii(cv.getColumn()), Hex.encNonAscii(cv.getValue()));
+ return cv;
+ });
+ }
+
+ @Override
+ public Bytes getRow() {
+ return cs.getRow();
+ }
+
+ @Override
+ public String getsRow() {
+ return cs.getsRow();
+ }
+
+}
diff --git a/modules/core/src/main/java/org/apache/fluo/core/log/TracingRowScanner.java b/modules/core/src/main/java/org/apache/fluo/core/log/TracingRowScanner.java
new file mode 100644
index 0000000..9796d40
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/fluo/core/log/TracingRowScanner.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.fluo.core.log;
+
+import java.util.Iterator;
+
+import com.google.common.collect.Iterators;
+import org.apache.fluo.api.client.scanner.ColumnScanner;
+import org.apache.fluo.api.client.scanner.RowScanner;
+
+public class TracingRowScanner implements RowScanner {
+ private final RowScanner wrappedScanner;
+ private final long txid;
+ private final String scanId;
+
+ TracingRowScanner(RowScanner wrappedScanner, long txid, String scanId) {
+ this.wrappedScanner = wrappedScanner;
+ this.txid = txid;
+ this.scanId = scanId;
+ }
+
+ @Override
+ public Iterator<ColumnScanner> iterator() {
+ return Iterators.transform(wrappedScanner.iterator(), cs -> {
+ return new TracingColumnScanner(cs, txid, scanId);
+ });
+ }
+
+}
diff --git a/modules/core/src/main/java/org/apache/fluo/core/log/TracingScannerBuilder.java b/modules/core/src/main/java/org/apache/fluo/core/log/TracingScannerBuilder.java
new file mode 100644
index 0000000..3964711
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/fluo/core/log/TracingScannerBuilder.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.fluo.core.log;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Objects;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.fluo.api.client.scanner.CellScanner;
+import org.apache.fluo.api.client.scanner.RowScanner;
+import org.apache.fluo.api.client.scanner.RowScannerBuilder;
+import org.apache.fluo.api.client.scanner.ScannerBuilder;
+import org.apache.fluo.api.config.FluoConfiguration;
+import org.apache.fluo.api.data.Column;
+import org.apache.fluo.api.data.Span;
+import org.apache.fluo.core.util.Hex;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TracingScannerBuilder implements ScannerBuilder {
+
+ private static final Logger log = LoggerFactory.getLogger(FluoConfiguration.TRANSACTION_PREFIX);
+
+ private static final Span EMPTY_SPAN = new Span();
+
+ private Span span = EMPTY_SPAN;
+ private Collection<Column> columns = Collections.emptyList();
+
+ private final ScannerBuilder wrappedBuilder;
+ private final long txid;
+
+ TracingScannerBuilder(ScannerBuilder wrappedBuilder, long txid) {
+ this.wrappedBuilder = wrappedBuilder;
+ this.txid = txid;
+ }
+
+ @Override
+ public ScannerBuilder over(Span span) {
+ Objects.requireNonNull(span);
+ this.span = span;
+ wrappedBuilder.over(span);
+ return this;
+ }
+
+ @Override
+ public ScannerBuilder fetch(Column... columns) {
+ Objects.requireNonNull(columns);
+ this.columns = ImmutableSet.copyOf(columns);
+ wrappedBuilder.fetch(this.columns);
+ return this;
+ }
+
+ @Override
+ public ScannerBuilder fetch(Collection<Column> columns) {
+ Objects.requireNonNull(columns);
+ this.columns = ImmutableSet.copyOf(columns);
+ wrappedBuilder.fetch(this.columns);
+ return this;
+ }
+
+ @Override
+ public CellScanner build() {
+ String scanId = Integer.toHexString(Math.abs(Objects.hash(span, columns, txid)));
+ log.trace("txid: {} scanId: {} scanner().over({}).fetch({}).build()", txid, scanId,
+ Hex.encNonAscii(span), Hex.encNonAscii(columns));
+ if (TracingCellScanner.log.isTraceEnabled()) {
+ return new TracingCellScanner(wrappedBuilder.build(), txid, scanId);
+ } else {
+ return wrappedBuilder.build();
+ }
+ }
+
+ @Override
+ public RowScannerBuilder byRow() {
+ String scanId = Integer.toHexString(Math.abs(Objects.hash(span, columns, txid)));
+ return new RowScannerBuilder() {
+ @Override
+ public RowScanner build() {
+ log.trace("txid: {} scanId: {} scanner().over({}).fetch({}).byRow().build()", txid, scanId,
+ Hex.encNonAscii(span), Hex.encNonAscii(columns));
+ if (TracingCellScanner.log.isTraceEnabled()) {
+ return new TracingRowScanner(wrappedBuilder.byRow().build(), txid, scanId);
+ } else {
+ return wrappedBuilder.byRow().build();
+ }
+ }
+ };
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/fluo/core/log/TracingTransaction.java b/modules/core/src/main/java/org/apache/fluo/core/log/TracingTransaction.java
index f9298de..db2fefb 100644
--- a/modules/core/src/main/java/org/apache/fluo/core/log/TracingTransaction.java
+++ b/modules/core/src/main/java/org/apache/fluo/core/log/TracingTransaction.java
@@ -156,9 +156,7 @@
@Override
public ScannerBuilder scanner() {
- // TODO log something better (see fluo-425)
- log.trace("txid: {} newScanner()", txid);
- return tx.scanner();
+ return new TracingScannerBuilder(tx.scanner(), txid);
}
@Override
diff --git a/modules/core/src/main/java/org/apache/fluo/core/util/Hex.java b/modules/core/src/main/java/org/apache/fluo/core/util/Hex.java
index f9fc85f..d2c1bd7 100644
--- a/modules/core/src/main/java/org/apache/fluo/core/util/Hex.java
+++ b/modules/core/src/main/java/org/apache/fluo/core/util/Hex.java
@@ -16,10 +16,12 @@
package org.apache.fluo.core.util;
import java.io.ByteArrayOutputStream;
+import java.util.Collection;
import org.apache.fluo.api.data.Bytes;
import org.apache.fluo.api.data.Column;
import org.apache.fluo.api.data.RowColumn;
+import org.apache.fluo.api.data.Span;
import org.apache.fluo.core.impl.Notification;
public class Hex {
@@ -59,6 +61,19 @@
return sb.toString();
}
+ public static Object encNonAscii(Collection<Column> columns) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ String sep = "";
+ for (Column column : columns) {
+ sb.append(sep);
+ encNonAscii(sb, column, " ");
+ sep = ",";
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
public static String encNonAscii(RowColumn rc) {
StringBuilder sb = new StringBuilder();
encNonAscii(sb, rc, " ");
@@ -79,6 +94,13 @@
return sb.toString();
}
+ public static String encNonAscii(Span span) {
+ return ((span.isStartInclusive() && !span.getStart().equals(RowColumn.EMPTY)) ? "[" : "(")
+ + (span.getStart().equals(RowColumn.EMPTY) ? "-inf" : encNonAscii(span.getStart())) + ","
+ + (span.getEnd().equals(RowColumn.EMPTY) ? "+inf" : encNonAscii(span.getEnd()))
+ + ((span.isEndInclusive() && !span.getEnd().equals(RowColumn.EMPTY)) ? "]" : ")");
+ }
+
static byte[] decode(String s) {
// the next best thing to a StringBuilder for bytes
diff --git a/modules/core/src/main/java/org/apache/fluo/core/worker/ObserverContext.java b/modules/core/src/main/java/org/apache/fluo/core/worker/ObserverContext.java
index fadea3e..47d5997 100644
--- a/modules/core/src/main/java/org/apache/fluo/core/worker/ObserverContext.java
+++ b/modules/core/src/main/java/org/apache/fluo/core/worker/ObserverContext.java
@@ -20,7 +20,6 @@
import org.apache.fluo.api.observer.Observer;
import org.apache.fluo.core.impl.Environment;
import org.apache.fluo.core.metrics.DummyMetricsReporter;
-import org.apache.fluo.core.metrics.MetricsReporterImpl;
public class ObserverContext implements Observer.Context {
diff --git a/modules/integration/src/test/java/org/apache/fluo/integration/impl/ObserverConfigIT.java b/modules/integration/src/test/java/org/apache/fluo/integration/impl/ObserverConfigIT.java
index a2c624f..bfd8e25 100644
--- a/modules/integration/src/test/java/org/apache/fluo/integration/impl/ObserverConfigIT.java
+++ b/modules/integration/src/test/java/org/apache/fluo/integration/impl/ObserverConfigIT.java
@@ -30,7 +30,6 @@
import org.apache.fluo.api.metrics.Counter;
import org.apache.fluo.api.metrics.Meter;
import org.apache.fluo.api.observer.AbstractObserver;
-import org.apache.fluo.api.metrics.MetricsReporter;
import org.apache.fluo.api.observer.Observer.NotificationType;
import org.apache.fluo.integration.ITBaseMini;
import org.junit.Assert;
diff --git a/modules/integration/src/test/java/org/apache/fluo/integration/log/LogIT.java b/modules/integration/src/test/java/org/apache/fluo/integration/log/LogIT.java
index c2167bc..02a4fd3 100644
--- a/modules/integration/src/test/java/org/apache/fluo/integration/log/LogIT.java
+++ b/modules/integration/src/test/java/org/apache/fluo/integration/log/LogIT.java
@@ -16,19 +16,29 @@
package org.apache.fluo.integration.log;
import java.io.StringWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import org.apache.fluo.api.client.Loader;
import org.apache.fluo.api.client.LoaderExecutor;
import org.apache.fluo.api.client.Snapshot;
import org.apache.fluo.api.client.Transaction;
import org.apache.fluo.api.client.TransactionBase;
+import org.apache.fluo.api.client.scanner.CellScanner;
+import org.apache.fluo.api.client.scanner.ColumnScanner;
+import org.apache.fluo.api.client.scanner.RowScanner;
import org.apache.fluo.api.config.ObserverSpecification;
import org.apache.fluo.api.data.Bytes;
import org.apache.fluo.api.data.Column;
+import org.apache.fluo.api.data.ColumnValue;
import org.apache.fluo.api.data.RowColumn;
+import org.apache.fluo.api.data.RowColumnValue;
+import org.apache.fluo.api.data.Span;
import org.apache.fluo.api.observer.AbstractObserver;
import org.apache.fluo.integration.ITBaseMini;
import org.apache.fluo.integration.TestUtil;
@@ -325,10 +335,19 @@
logger.addAppender(appender);
try (Snapshot snap = client.newSnapshot()) {
- snap.gets(Arrays.asList(new RowColumn("r1", c1), new RowColumn("r2", c2)));
- snap.gets(Arrays.asList("r1", "r2"), ImmutableSet.of(c1));
- snap.gets("r1", ImmutableSet.of(c1, c2));
- snap.gets("r1", c1);
+ Map<RowColumn, String> ret1 =
+ snap.gets(Arrays.asList(new RowColumn("r1", c1), new RowColumn("r2", c2)));
+ Assert.assertEquals(
+ ImmutableMap.of(new RowColumn("r1", c1), "v1", new RowColumn("r2", c2), "v4"), ret1);
+ Map<String, Map<Column, String>> ret2 =
+ snap.gets(Arrays.asList("r1", "r2"), ImmutableSet.of(c1));
+ Assert
+ .assertEquals(
+ ImmutableMap.of("r1", ImmutableMap.of(c1, "v1"), "r2", ImmutableMap.of(c1, "v3")),
+ ret2);
+ Map<Column, String> ret3 = snap.gets("r1", ImmutableSet.of(c1, c2));
+ Assert.assertEquals(ImmutableMap.of(c1, "v1", c2, "v2"), ret3);
+ Assert.assertEquals("v1", snap.gets("r1", c1));
}
miniFluo.waitForObservers();
@@ -412,4 +431,137 @@
pattern += ".*";
Assert.assertTrue(origLogMsgs, logMsgs.matches(pattern));
}
+
+ private void assertEqual(CellScanner cs, RowColumnValue... rcvs) {
+ ArrayList<RowColumnValue> actual = new ArrayList<>();
+ Iterables.addAll(actual, cs);
+ Assert.assertEquals(Arrays.asList(rcvs), actual);
+ }
+
+ private void assertEqual(RowScanner rs, Object... stuff) {
+ int i = 0;
+ for (ColumnScanner cs : rs) {
+ Assert.assertEquals(stuff[i++], cs.getsRow());
+ for (ColumnValue cv : cs) {
+ Assert.assertEquals(stuff[i++], cv.getColumn());
+ Assert.assertEquals(stuff[i++], cv.getsValue());
+ }
+ }
+
+ Assert.assertEquals(stuff.length, i);
+ }
+
+ @Test
+ public void testScanLogging() {
+ Column c1 = new Column("f1", "q1");
+ Column c2 = new Column("f1", "q2");
+
+ try (Transaction tx = client.newTransaction()) {
+ tx.set("r1", c1, "v1");
+ tx.set("r1", c2, "v2");
+ tx.set("r2", c1, "v3");
+ tx.set("r2", c2, "v4");
+ tx.commit();
+ }
+
+ Logger logger = Logger.getLogger("fluo.tx");
+
+ StringWriter writer = new StringWriter();
+ WriterAppender appender =
+ new WriterAppender(new PatternLayout("%d{ISO8601} [%-8c{2}] %-5p: %m%n"), writer);
+
+ Level level = logger.getLevel();
+ boolean additivity = logger.getAdditivity();
+
+ try {
+ logger.setLevel(Level.TRACE);
+ logger.setAdditivity(false);
+ logger.addAppender(appender);
+
+ try (Snapshot snap = client.newSnapshot()) {
+ RowColumnValue rcv1 = new RowColumnValue("r1", c1, "v1");
+ RowColumnValue rcv2 = new RowColumnValue("r1", c2, "v2");
+ RowColumnValue rcv3 = new RowColumnValue("r2", c1, "v3");
+ RowColumnValue rcv4 = new RowColumnValue("r2", c2, "v4");
+
+ CellScanner scanner1 = snap.scanner().build();
+ assertEqual(scanner1, rcv1, rcv2, rcv3, rcv4);
+
+ CellScanner scanner2 = snap.scanner().over(Span.exact("r1")).build();
+ assertEqual(scanner2, rcv1, rcv2);
+
+ CellScanner scanner3 = snap.scanner().over(Span.exact("r1")).fetch(c1).build();
+ assertEqual(scanner3, rcv1);
+
+ CellScanner scanner4 = snap.scanner().fetch(c1).build();
+ assertEqual(scanner4, rcv1, rcv3);
+ }
+
+ try (Snapshot snap = client.newSnapshot()) {
+ RowScanner rowScanner1 = snap.scanner().byRow().build();
+ assertEqual(rowScanner1, "r1", c1, "v1", c2, "v2", "r2", c1, "v3", c2, "v4");
+
+ RowScanner rowScanner2 = snap.scanner().over(Span.exact("r1")).byRow().build();
+ assertEqual(rowScanner2, "r1", c1, "v1", c2, "v2");
+
+ RowScanner rowScanner3 = snap.scanner().over(Span.exact("r1")).fetch(c1).byRow().build();
+ assertEqual(rowScanner3, "r1", c1, "v1");
+
+ RowScanner rowScanner4 = snap.scanner().fetch(c1).byRow().build();
+ assertEqual(rowScanner4, "r1", c1, "v1", "r2", c1, "v3");
+ }
+
+ } finally {
+ logger.removeAppender(appender);
+ logger.setAdditivity(additivity);
+ logger.setLevel(level);
+ }
+
+ String origLogMsgs = writer.toString();
+ String logMsgs = origLogMsgs.replace('\n', ' ');
+
+ String pattern = "";
+
+ pattern += ".*txid: (\\d+) begin\\(\\) thread: \\d+";
+ pattern +=
+ ".*txid: \\1 scanId: ([0-9a-f]+) \\Qscanner().over((-inf,+inf)).fetch([]).build()\\E";
+ pattern += ".*txid: \\1 scanId: \\2 \\Qnext()-> r1 f1 q1 v1\\E";
+ pattern += ".*txid: \\1 scanId: \\2 \\Qnext()-> r1 f1 q2 v2\\E";
+ pattern += ".*txid: \\1 scanId: \\2 \\Qnext()-> r2 f1 q1 v3\\E";
+ pattern += ".*txid: \\1 scanId: \\2 \\Qnext()-> r2 f1 q2 v4\\E";
+ pattern +=
+ ".*txid: \\1 scanId: ([0-9a-f]+) \\Qscanner().over([r1 ,r1\\x00 )).fetch([]).build()\\E";
+ pattern += ".*txid: \\1 scanId: \\3 \\Qnext()-> r1 f1 q1 v1\\E";
+ pattern += ".*txid: \\1 scanId: \\3 \\Qnext()-> r1 f1 q2 v2\\E";
+ pattern +=
+ ".*txid: \\1 scanId: ([0-9a-f]+) \\Qscanner().over([r1 ,r1\\x00 )).fetch([f1 q1 ]).build()\\E";
+ pattern += ".*txid: \\1 scanId: \\4 \\Qnext()-> r1 f1 q1 v1\\E";
+ pattern +=
+ ".*txid: \\1 scanId: ([0-9a-f]+) \\Qscanner().over((-inf,+inf)).fetch([f1 q1 ]).build()\\E";
+ pattern += ".*txid: \\1 scanId: \\5 \\Qnext()-> r1 f1 q1 v1\\E";
+ pattern += ".*txid: \\1 scanId: \\5 \\Qnext()-> r2 f1 q1 v3\\E";
+ pattern += ".*txid: \\1 \\Qclose()\\E";
+ pattern += ".*txid: (\\d+) begin\\(\\) thread: \\d+";
+ pattern +=
+ ".*txid: \\6 scanId: ([0-9a-f]+) \\Qscanner().over((-inf,+inf)).fetch([]).byRow().build()\\E";
+ pattern += ".*txid: \\6 scanId: \\7 \\Qnext()-> r1 f1 q1 v1\\E";
+ pattern += ".*txid: \\6 scanId: \\7 \\Qnext()-> r1 f1 q2 v2\\E";
+ pattern += ".*txid: \\6 scanId: \\7 \\Qnext()-> r2 f1 q1 v3\\E";
+ pattern += ".*txid: \\6 scanId: \\7 \\Qnext()-> r2 f1 q2 v4\\E";
+ pattern +=
+ ".*txid: \\6 scanId: ([0-9a-f]+) \\Qscanner().over([r1 ,r1\\x00 )).fetch([]).byRow().build()\\E";
+ pattern += ".*txid: \\6 scanId: \\8 \\Qnext()-> r1 f1 q1 v1\\E";
+ pattern += ".*txid: \\6 scanId: \\8 \\Qnext()-> r1 f1 q2 v2\\E";
+ pattern +=
+ ".*txid: \\6 scanId: ([0-9a-f]+) \\Qscanner().over([r1 ,r1\\x00 )).fetch([f1 q1 ]).byRow().build()\\E";
+ pattern += ".*txid: \\6 scanId: \\9 \\Qnext()-> r1 f1 q1 v1\\E";
+ pattern +=
+ ".*txid: \\6 scanId: ([0-9a-f]+) \\Qscanner().over((-inf,+inf)).fetch([f1 q1 ]).byRow().build()\\E";
+ pattern += ".*txid: \\6 scanId: \\10 \\Qnext()-> r1 f1 q1 v1\\E";
+ pattern += ".*txid: \\6 scanId: \\10 \\Qnext()-> r2 f1 q1 v3\\E";
+ pattern += ".*txid: \\6 \\Qclose()\\E.*";
+
+ Assert.assertTrue(origLogMsgs, logMsgs.matches(pattern));
+
+ }
}