This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new 5441f58f4c MQE: check the metrics value before do binary operation to 
improve robustness (#12483)
5441f58f4c is described below

commit 5441f58f4cf2a3404a5035ffd594d54a32800c23
Author: Wan Kai <[email protected]>
AuthorDate: Fri Jul 26 18:49:33 2024 +0800

    MQE: check the metrics value before do binary operation to improve 
robustness (#12483)
---
 docs/en/changes/changes.md                         |  1 +
 .../skywalking/mqe/rt/operation/BinaryOp.java      |  2 +-
 .../skywalking/mqe/rt/operation/CompareOp.java     |  2 +-
 .../apache/skywalking/mqe/rt/operation/LROp.java   | 65 ++++++++++++++++++----
 .../org/apache/skywalking/mqe/rt/BinaryOpTest.java | 38 +++++++++++++
 .../org/apache/skywalking/mqe/rt/MockData.java     |  7 +++
 test/e2e-v2/script/env                             |  2 +-
 7 files changed, 104 insertions(+), 13 deletions(-)

diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md
index 12559cc48b..7a6d526e80 100644
--- a/docs/en/changes/changes.md
+++ b/docs/en/changes/changes.md
@@ -38,6 +38,7 @@
 * Support BanyanDB internal stream query execution tracing.
 * Fix Elasticsearch, MySQL, RabbitMQ dashboards typos and missing expressions.
 * BanyanDB: Zipkin Module set service as Entity for improving the query 
performance.
+* MQE: check the metrics value before do binary operation to improve 
robustness.
 
 #### UI
 
diff --git 
a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/BinaryOp.java
 
b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/BinaryOp.java
index 00bfec134f..0c84aaf983 100644
--- 
a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/BinaryOp.java
+++ 
b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/BinaryOp.java
@@ -29,7 +29,7 @@ public class BinaryOp {
         try {
             return LROp.doLROp(left, right, opType, BinaryOp::scalarBinaryOp);
         } catch (IllegalExpressionException e) {
-            throw new IllegalExpressionException("Unsupported binary 
operation.");
+            throw new IllegalExpressionException("Unsupported binary 
operation: " + e.getMessage());
         }
     }
 
diff --git 
a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/CompareOp.java
 
b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/CompareOp.java
index 499e7ca79e..030f3174fd 100644
--- 
a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/CompareOp.java
+++ 
b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/CompareOp.java
@@ -29,7 +29,7 @@ public class CompareOp {
         try {
             return LROp.doLROp(left, right, opType, 
CompareOp::scalarCompareOp);
         } catch (IllegalExpressionException e) {
-            throw new IllegalExpressionException("Unsupported compare 
operation.");
+            throw new IllegalExpressionException("Unsupported compare 
operation: " + e.getMessage());
         }
     }
 
diff --git 
a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/LROp.java
 
b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/LROp.java
index c86ae61893..4254b59898 100644
--- 
a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/LROp.java
+++ 
b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/LROp.java
@@ -91,7 +91,17 @@ public interface LROp {
 
     private static ExpressionResult single2SingleNoLabeled(ExpressionResult 
singleLeft,
                                                           ExpressionResult 
singleRight,
-                                                          int opType, LROp 
calculate) {
+                                                          int opType, LROp 
calculate) throws IllegalExpressionException {
+        if (singleLeft.getResults().isEmpty() ||
+            singleLeft.getResults().get(0).getValues().size() != 1) {
+            throw new IllegalExpressionException("Single to Single, left 
result is empty or has more than one value.");
+        }
+
+        if (singleRight.getResults().isEmpty() ||
+            singleRight.getResults().get(0).getValues().size() != 1) {
+            throw new IllegalExpressionException("Single to Single, right 
result is empty or has more than one value.");
+        }
+
         ExpressionResult result = new ExpressionResult();
         MQEValue mqeValue = new MQEValue();
         MQEValues mqeValues = new MQEValues();
@@ -119,12 +129,18 @@ public interface LROp {
             labelMapR.put(new HashSet<>(mqeValuesR.getMetric().getLabels()), 
mqeValuesR.getValues());
         });
         for (MQEValues mqeValuesL : singleLeft.getResults()) {
+            if (mqeValuesL.getValues().size() != 1) {
+                throw new IllegalExpressionException("Single Labeled to Single 
Labeled, left labeled result is empty or has more than one value.");
+            }
             //reserve left metric info
             MQEValue valueL = mqeValuesL.getValues().get(0);
             List<MQEValue> mqeValuesR = labelMapR.get(new 
HashSet<>(mqeValuesL.getMetric().getLabels()));
             if (mqeValuesR == null) {
                 valueL.setEmptyValue(true);
             } else {
+                if (mqeValuesR.size() != 1) {
+                    throw new IllegalExpressionException("Single Labeled to 
Single Labeled, right labeled result has more than one value.");
+                }
                 MQEValue valueR = mqeValuesR.get(0);
                 if (valueL.isEmptyValue() || valueR.isEmptyValue()) {
                     valueL.setEmptyValue(true);
@@ -141,7 +157,11 @@ public interface LROp {
     //series or list or labeled single value with scalar
     private static ExpressionResult many2OneBinaryOp(ExpressionResult 
manyResult,
                                                      ExpressionResult 
singleResult,
-                                                     int opType, LROp 
calculate) {
+                                                     int opType, LROp 
calculate) throws IllegalExpressionException {
+        if (singleResult.getResults().isEmpty() ||
+            singleResult.getResults().get(0).getValues().size() != 1) {
+            throw new IllegalExpressionException("Many to One, single result 
is empty or has more than one value.");
+        }
         manyResult.getResults().forEach(mqeValues -> {
             mqeValues.getValues().forEach(mqeValue -> {
                 if (!mqeValue.isEmptyValue()) {
@@ -161,7 +181,11 @@ public interface LROp {
     //scalar with series or list or labeled single value
     private static ExpressionResult one2ManyBinaryOp(ExpressionResult 
singleResult,
                                                      ExpressionResult 
manyResult,
-                                                     int opType, LROp 
calculate) {
+                                                     int opType, LROp 
calculate) throws IllegalExpressionException {
+        if (singleResult.getResults().isEmpty() ||
+            singleResult.getResults().get(0).getValues().size() != 1) {
+            throw new IllegalExpressionException("One to Many, single result 
is empty or has more than one value.");
+        }
         manyResult.getResults().forEach(mqeValues -> {
             mqeValues.getValues().forEach(mqeValue -> {
                 if (!mqeValue.isEmptyValue()) {
@@ -182,9 +206,15 @@ public interface LROp {
 
     private static ExpressionResult seriesNoLabeled(ExpressionResult 
seriesLeft,
                                                     ExpressionResult 
seriesRight,
-                                                    int opType, LROp 
calculate) {
+                                                    int opType, LROp 
calculate) throws IllegalExpressionException {
+        if (seriesLeft.getResults().isEmpty() || 
seriesRight.getResults().isEmpty()) {
+            throw new IllegalExpressionException("Series No Labeled, left or 
right result is empty.");
+        }
         MQEValues mqeValuesL = seriesLeft.getResults().get(0);
         MQEValues mqeValuesR = seriesRight.getResults().get(0);
+        if (mqeValuesL.getValues().size() != mqeValuesR.getValues().size()) {
+            throw new IllegalExpressionException("Series No Labeled, left and 
right series value size not equal.");
+        }
         for (int i = 0; i < mqeValuesL.getValues().size(); i++) {
             //clean metric info
             MQEValue valueL = mqeValuesL.getValues().get(i);
@@ -203,9 +233,15 @@ public interface LROp {
 
     private static ExpressionResult 
seriesLabeledWithNoLabeled(ExpressionResult seriesLeft,
                                                                
ExpressionResult seriesRight,
-                                                               int opType, 
LROp calculate) {
+                                                               int opType, 
LROp calculate) throws IllegalExpressionException {
+        if (seriesRight.getResults().isEmpty()) {
+            throw new IllegalExpressionException("Series Labeled with No 
Labeled, no labeled result is empty.");
+        }
         MQEValues mqeValuesR = seriesRight.getResults().get(0);
-        seriesLeft.getResults().forEach(mqeValuesL -> {
+        for (MQEValues mqeValuesL : seriesLeft.getResults()) {
+            if (mqeValuesL.getValues().size() != 
mqeValuesR.getValues().size()) {
+                throw new IllegalExpressionException("Series Labeled with No 
Labeled, left and right series value size not equal.");
+            }
             for (int i = 0; i < mqeValuesL.getValues().size(); i++) {
                 //reserve left metric info
                 MQEValue valueL = mqeValuesL.getValues().get(i);
@@ -217,16 +253,22 @@ public interface LROp {
                 double newValue = calculate.apply(valueL.getDoubleValue(), 
valueR.getDoubleValue(), opType);
                 mqeValuesL.getValues().get(i).setDoubleValue(newValue);
             }
-        });
+        }
 
         return seriesLeft;
     }
 
     private static ExpressionResult 
seriesNoLabeledWithLabeled(ExpressionResult seriesLeft,
                                                                
ExpressionResult seriesRight,
-                                                               int opType, 
LROp calculate) {
+                                                               int opType, 
LROp calculate) throws IllegalExpressionException {
+        if (seriesLeft.getResults().isEmpty()) {
+            throw new IllegalExpressionException("Series No Labeled with 
Labeled, no labeled result is empty.");
+        }
         MQEValues mqeValuesL = seriesLeft.getResults().get(0);
-        seriesRight.getResults().forEach(mqeValuesR -> {
+        for (MQEValues mqeValuesR : seriesRight.getResults()) {
+            if (mqeValuesL.getValues().size() != 
mqeValuesR.getValues().size()) {
+                throw new IllegalExpressionException("Series No Labeled with 
Labeled, left and right series value size not equal.");
+            }
             for (int i = 0; i < mqeValuesL.getValues().size(); i++) {
                 //reserve left metric info
                 MQEValue valueL = mqeValuesL.getValues().get(i);
@@ -238,7 +280,7 @@ public interface LROp {
                 double newValue = calculate.apply(valueL.getDoubleValue(), 
valueR.getDoubleValue(), opType);
                 mqeValuesR.getValues().get(i).setDoubleValue(newValue);
             }
-        });
+        }
 
         return seriesRight;
     }
@@ -258,6 +300,9 @@ public interface LROp {
                 if (mqeValuesR == null) {
                     valueL.setEmptyValue(true);
                 } else {
+                    if (mqeValuesR.size() != mqeValuesL.getValues().size()) {
+                        throw new IllegalExpressionException("Series Labeled 
with Labeled, left and right series value size not equal.");
+                    }
                     MQEValue valueR = mqeValuesR.get(i);
                     if (valueL.isEmptyValue() || valueR.isEmptyValue()) {
                         valueL.setEmptyValue(true);
diff --git 
a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/BinaryOpTest.java
 
b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/BinaryOpTest.java
index 74b458c106..ea5e3d56f3 100644
--- 
a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/BinaryOpTest.java
+++ 
b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/BinaryOpTest.java
@@ -26,6 +26,7 @@ import org.apache.skywalking.mqe.rt.type.ExpressionResultType;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 public class BinaryOpTest {
     private final MockData mockData = new MockData();
@@ -33,6 +34,10 @@ public class BinaryOpTest {
     //DIV/MUL/MOD/SUB... are the same logic and tested in here, the others 
only test ADD is enough.
     @Test
     public void seriesNoLabeledTest() throws Exception {
+        assertThrows(IllegalExpressionException.class, () -> 
BinaryOp.doBinaryOp(
+            mockData.newEmptyResult(ExpressionResultType.TIME_SERIES_VALUES, 
false),
+            mockData.newEmptyResult(ExpressionResultType.TIME_SERIES_VALUES, 
false), MQEParser.ADD
+        ));
         ExpressionResult add = BinaryOp.doBinaryOp(
             mockData.newSeriesNoLabeledResult(), 
mockData.newSeriesNoLabeledResult(), MQEParser.ADD);
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, add.getType());
@@ -76,6 +81,10 @@ public class BinaryOpTest {
 
     @Test
     public void seriesLabeledTest() throws Exception {
+        assertThrows(IllegalExpressionException.class, () -> 
BinaryOp.doBinaryOp(
+            mockData.newSeriesLabeledResult(),
+            mockData.newEmptyResult(ExpressionResultType.TIME_SERIES_VALUES, 
false), MQEParser.ADD
+        ));
         //seriesLabeled + seriesNoLabeled
         ExpressionResult add = 
BinaryOp.doBinaryOp(mockData.newSeriesLabeledResult(), 
mockData.newSeriesNoLabeledResult(), MQEParser.ADD);
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, add.getType());
@@ -133,6 +142,18 @@ public class BinaryOpTest {
 
     @Test
     public void many2OneTest() throws Exception {
+        assertThrows(IllegalExpressionException.class, () -> 
BinaryOp.doBinaryOp(
+            mockData.newEmptyResult(ExpressionResultType.TIME_SERIES_VALUES, 
false),
+            mockData.newEmptyResult(ExpressionResultType.SINGLE_VALUE, false), 
MQEParser.ADD
+        ));
+        assertThrows(IllegalExpressionException.class, () -> 
BinaryOp.doBinaryOp(
+            mockData.newEmptyResult(ExpressionResultType.TIME_SERIES_VALUES, 
true),
+            mockData.newEmptyResult(ExpressionResultType.SINGLE_VALUE, false), 
MQEParser.ADD
+        ));
+        assertThrows(IllegalExpressionException.class, () -> 
BinaryOp.doBinaryOp(
+            mockData.newEmptyResult(ExpressionResultType.TIME_SERIES_VALUES, 
false),
+            mockData.newEmptyResult(ExpressionResultType.SINGLE_VALUE, true), 
MQEParser.ADD
+        ));
         //sort_list + single
         ExpressionResult add = BinaryOp.doBinaryOp(
             mockData.newListResult(), mockData.newSingleResult(1000), 
MQEParser.ADD);
@@ -171,6 +192,14 @@ public class BinaryOpTest {
 
     @Test
     public void one2ManyTest() throws Exception {
+        assertThrows(IllegalExpressionException.class, () -> 
BinaryOp.doBinaryOp(
+            mockData.newEmptyResult(ExpressionResultType.SINGLE_VALUE, false),
+            mockData.newEmptyResult(ExpressionResultType.TIME_SERIES_VALUES, 
false), MQEParser.ADD
+        ));
+        assertThrows(IllegalExpressionException.class, () -> 
BinaryOp.doBinaryOp(
+            mockData.newEmptyResult(ExpressionResultType.SINGLE_VALUE, false),
+            mockData.newEmptyResult(ExpressionResultType.TIME_SERIES_VALUES, 
true), MQEParser.ADD
+        ));
         // single - sort_list
         ExpressionResult sub = BinaryOp.doBinaryOp(
             mockData.newSingleResult(1000), mockData.newListResult(), 
MQEParser.SUB);
@@ -209,6 +238,15 @@ public class BinaryOpTest {
 
     @Test
     public void single2SingleTest() throws IllegalExpressionException {
+        assertThrows(IllegalExpressionException.class, () -> 
BinaryOp.doBinaryOp(
+            mockData.newEmptyResult(ExpressionResultType.SINGLE_VALUE, false),
+            mockData.newEmptyResult(ExpressionResultType.SINGLE_VALUE, false), 
MQEParser.ADD
+        ));
+        assertThrows(IllegalExpressionException.class, () -> 
BinaryOp.doBinaryOp(
+            mockData.newEmptyResult(ExpressionResultType.SINGLE_VALUE, false),
+            mockData.newEmptyResult(ExpressionResultType.SINGLE_VALUE, true), 
MQEParser.ADD
+        ));
+
         //noLabeled + noLabeled
         ExpressionResult add = BinaryOp.doBinaryOp(
             mockData.newSingleResult(100), mockData.newSingleResult(200), 
MQEParser.ADD);
diff --git 
a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/MockData.java 
b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/MockData.java
index 2a53df8f0d..ff25c1e997 100644
--- a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/MockData.java
+++ b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/MockData.java
@@ -185,6 +185,13 @@ public class MockData {
         return result;
     }
 
+    public ExpressionResult newEmptyResult(ExpressionResultType type, boolean 
labeled) {
+        ExpressionResult result = new ExpressionResult();
+        result.setType(type);
+        result.setLabeledResult(labeled);
+        return result;
+    }
+
     public MQEValue newMQEValue(String id, double value) {
         MQEValue mqeValue = new MQEValue();
         mqeValue.setId(id);
diff --git a/test/e2e-v2/script/env b/test/e2e-v2/script/env
index 3d61b338bd..b495437dde 100644
--- a/test/e2e-v2/script/env
+++ b/test/e2e-v2/script/env
@@ -23,7 +23,7 @@ 
SW_AGENT_CLIENT_JS_COMMIT=af0565a67d382b683c1dbd94c379b7080db61449
 SW_AGENT_CLIENT_JS_TEST_COMMIT=4f1eb1dcdbde3ec4a38534bf01dded4ab5d2f016
 SW_KUBERNETES_COMMIT_SHA=1335f15bf821a40a7cd71448fa805f0be265afcc
 SW_ROVER_COMMIT=6bbd39aa701984482330d9dfb4dbaaff0527d55c
-SW_BANYANDB_COMMIT=285db188e633c6b95b8c5c354e043db79658c147
+SW_BANYANDB_COMMIT=6f938ccf812e2183b4bd891fb90b2124aa65c170
 SW_AGENT_PHP_COMMIT=3192c553002707d344bd6774cfab5bc61f67a1d3
 
 SW_CTL_COMMIT=d5f3597733aa5217373986d776a3ee5ee8b3c468

Reply via email to