This is an automated email from the ASF dual-hosted git repository. leirui pushed a commit to branch research/LTS-visualization in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 99576c5372c8fc2321faefab75bff7b6ecc36959 Author: Lei Rui <[email protected]> AuthorDate: Sun Jan 28 02:07:37 2024 +0800 minmaxLTTB --- .../dataset/groupby/GroupByEngineDataSet.java | 6 +- .../groupby/GroupByWithoutValueFilterDataSet.java | 217 +++++++++++++++++---- .../groupby/LocalGroupByExecutorTri_MinMax.java | 6 +- .../iotdb/db/integration/tri/MyTest_MinMax.java | 10 +- .../{MyTest_MinMax.java => MyTest_MinMaxLTTB.java} | 107 ++++++++-- .../iotdb/tsfile/read/common/IOMonitor2.java | 5 + 6 files changed, 294 insertions(+), 57 deletions(-) diff --git a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByEngineDataSet.java b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByEngineDataSet.java index 7194633765d..8feafc55602 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByEngineDataSet.java +++ b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByEngineDataSet.java @@ -129,7 +129,11 @@ public abstract class GroupByEngineDataSet extends QueryDataSet { curStartTime += curSlidingStep; } // This is an open interval , [0-100) - if (curStartTime >= endTime) { + if (curStartTime + interval >= endTime) { + // + interval to make the last bucket complete + // e.g, T=11,nout=3,interval=floor(11/3)=3, + // [0,3),[3,6),[6,9), no need incomplete [9,11) + // then the number of buckets must be Math.floor((endTime-startTime)/interval) return false; } } else { diff --git a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithoutValueFilterDataSet.java b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithoutValueFilterDataSet.java index 9472f1f62fa..71538e8c3dd 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithoutValueFilterDataSet.java +++ b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/GroupByWithoutValueFilterDataSet.java @@ -33,6 +33,7 @@ import org.apache.iotdb.db.query.factory.AggregateResultFactory; import org.apache.iotdb.db.query.filter.TsFileFilter; import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor; import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; +import org.apache.iotdb.tsfile.file.metadata.statistics.MinMaxInfo; import org.apache.iotdb.tsfile.read.common.IOMonitor2; import org.apache.iotdb.tsfile.read.common.IOMonitor2.DataSetType; import org.apache.iotdb.tsfile.read.common.Path; @@ -132,37 +133,13 @@ public class GroupByWithoutValueFilterDataSet extends GroupByEngineDataSet { } } - /** Each row correspond to result of a bucket */ - public List<List<AggregateResult>> getAll() throws IOException, QueryProcessException { - List<List<AggregateResult>> resultsAllBuckets = new ArrayList<>(); - GroupByExecutor executor = null; - for (Entry<PartialPath, GroupByExecutor> pathToExecutorEntry : pathExecutors.entrySet()) { - executor = pathToExecutorEntry.getValue(); // assume only one series here - break; - } - for (long localCurStartTime = startTime; - localCurStartTime < endTime; - localCurStartTime += interval) { // not change real curStartTime&curEndTime - List<AggregateResult> aggregations = - executor.calcResult( - localCurStartTime, localCurStartTime + interval, startTime, endTime, interval); - resultsAllBuckets.add(aggregations); // needs deep copy!! - } - - // make the next hasNextWithoutConstraint() false - curStartTime = endTime; - hasCachedTimeInterval = false; - - return resultsAllBuckets; - } - @Override public RowRecord nextWithoutConstraint() throws IOException { if (CONFIG.getEnableTri().equals("MinMax")) { return nextWithoutConstraintTri_MinMax(); + } else if (CONFIG.getEnableTri().equals("MinMaxLTTB")) { + return nextWithoutConstraintTri_MinMaxLTTB(); } - // } else if (CONFIG.getEnableTri().equals("MinMaxLTTB")) { - // // TODO // } else if (CONFIG.getEnableTri().equals("M4LTTB")) { // // TODO // } else if (CONFIG.getEnableTri().equals("LTTB")) { @@ -175,6 +152,182 @@ public class GroupByWithoutValueFilterDataSet extends GroupByEngineDataSet { } } + public RowRecord nextWithoutConstraintTri_MinMaxLTTB() throws IOException { + RowRecord record; + + // TODO tmp p1,pn,rps later passed by config + long p1t = 0; + double p1v = -1.2079272; + long pnt = 2100; + double pnv = -0.0211206; + int rps = 4; + int divide = 2; // one LTTB bucket corresponds to rps/2 MinMax buckets + + // concat results into a string + record = new RowRecord(0); + StringBuilder series = new StringBuilder(); + + try { + // First step: get the MinMax preselection result + List<Long> times = new ArrayList<>(); + List<Object> values = new ArrayList<>(); + GroupByExecutor executor = null; + for (Entry<PartialPath, GroupByExecutor> pathToExecutorEntry : pathExecutors.entrySet()) { + executor = pathToExecutorEntry.getValue(); // assume only one series here + break; + } + for (long localCurStartTime = startTime; + localCurStartTime + interval <= endTime; + // 注意有等号! + // + interval to make the last bucket complete + // e.g, T=11,nout=3,interval=floor(11/3)=3, + // [0,3),[3,6),[6,9), no need incomplete [9,11) + // then the number of buckets must be Math.floor((endTime-startTime)/interval) + localCurStartTime += interval) { + System.out.println(localCurStartTime); + // not change real curStartTime&curEndTime + // attention the returned aggregations need deep copy if using directly + List<AggregateResult> aggregations = + executor.calcResult( + localCurStartTime, localCurStartTime + interval, startTime, endTime, interval); + for (AggregateResult aggregation : aggregations) { + // Each row correspond to (bucketLeftBound, minV[bottomT], maxV[topT]) of a MinMax bucket + MinMaxInfo minMaxInfo = (MinMaxInfo) aggregation.getResult(); + if (minMaxInfo == null) { + times.add(null); + values.add(null); + } else { + times.add(minMaxInfo.timestamp); + values.add(minMaxInfo.val); + } + } + } + + // Second step: apply LTTB on the MinMax preselection result + System.out.println(times); + System.out.println(values); + int N1 = (int) Math.floor((endTime * 1.0 - startTime) / interval); // MinMax桶数 + int N2 = N1 / (rps / divide); // LTTB桶数 + // 全局首点 + series.append(p1v).append("[").append(p1t).append("]").append(","); + long lt = p1t; // left fixed t + double lv = p1v; // left fixed v + // 找第一个不为空的LTTB当前桶 + int currentBucket = 0; + for (; currentBucket < N2; currentBucket++) { + boolean emptyBucket = true; + for (int j = currentBucket * rps; j < (currentBucket + 1) * rps; j++) { + // 一个LTTB桶里有rps个MinMax预选点(包含重复和null) + if (times.get(j) != null) { + emptyBucket = false; // 只要有一个MinMax预选点不是null,这个LTTB桶就不是空桶 + break; + } + } + if (!emptyBucket) { + break; + } + } + // 现在找到了不为空的LTTB当前桶,下面找第一个不为空的LTTB右边桶 + for (int nextBucket = currentBucket + 1; nextBucket < N2; nextBucket++) { + boolean emptyBucket = true; + for (int j = nextBucket * rps; j < (nextBucket + 1) * rps; j++) { + // 一个LTTB桶里有rps个MinMax预选点(包含重复和null) + if (times.get(j) != null) { + emptyBucket = false; // 只要有一个MinMax预选点不是null,这个LTTB桶就不是空桶 + break; + } + } + if (emptyBucket) { + continue; // 继续往右边找非空桶 + } + + // 现在计算右边非空LTTB桶的平均点 + double rt = 0; + double rv = 0; + int cnt = 0; + for (int j = nextBucket * rps; j < (nextBucket + 1) * rps; j++) { + // 一个LTTB桶里有rps个MinMax预选点(包含重复和null) + if (times.get(j) != null) { + rt += times.get(j); + rv += (double) values.get(j); // TODO + cnt++; + } + } + rt = rt / cnt; + rv = rv / cnt; + + // 现在找到当前非空桶里距离lr垂直距离最远的点 + double maxArea = -1; + long select_t = -1; + double select_v = -1; + for (int j = currentBucket * rps; j < (currentBucket + 1) * rps; j++) { + // 一个LTTB桶里有rps个MinMax预选点(包含重复和null) + if (times.get(j) != null) { + long t = times.get(j); + double v = (double) values.get(j); // TODO + double area = IOMonitor2.calculateTri(lt, lv, t, v, rt, rv); + System.out.printf("curr=%d,t=%d,area=%f,lt=%d%n", currentBucket, t, area, lt); + if (area > maxArea) { + maxArea = area; + select_t = t; + select_v = v; + } + } + } + if (select_t < 0) { + throw new IOException("something is wrong"); + } + series.append(select_v).append("[").append(select_t).append("]").append(","); + + // 现在更新当前桶和左边固定点,并且把结果点加到series里 + currentBucket = nextBucket; + lt = select_t; + lv = select_v; + } + + // 下面处理最后一个桶 + // 现在找到当前非空桶里距离lr垂直距离最远的点 + double maxArea = -1; + long select_t = -1; + double select_v = -1; + for (int j = currentBucket * rps; j < (currentBucket + 1) * rps; j++) { + // 一个LTTB桶里有rps个MinMax预选点(包含重复和null) + if (times.get(j) != null) { + long t = times.get(j); + double v = (double) values.get(j); // TODO + double area = IOMonitor2.calculateTri(lt, lv, t, v, pnt, pnv); // 全局尾点作为右边固定点 + System.out.printf("curr=%d,t=%d,area=%f,lt=%d%n", currentBucket, t, area, lt); + if (area > maxArea) { + maxArea = area; + select_t = t; + select_v = v; + } + } + } + if (select_t < 0) { + throw new IOException("something is wrong"); + } + series.append(select_v).append("[").append(select_t).append("]").append(","); + + // 全局尾点 + series.append(pnv).append("[").append(pnt).append("]").append(","); + + // MIN_MAX_INT64 this type for field.setBinaryV(new Binary(value.toString())) + record.addField(series, TSDataType.MIN_MAX_INT64); + + } catch (QueryProcessException e) { + logger.error("GroupByWithoutValueFilterDataSet execute has error", e); + throw new IOException(e.getMessage(), e); + } + + // in the end, make the next hasNextWithoutConstraint() false + // as we already fetch all here + curStartTime = endTime; + hasCachedTimeInterval = false; + + return record; + } + public RowRecord nextWithoutConstraintTri_MinMax() throws IOException { RowRecord record; try { @@ -189,7 +342,10 @@ public class GroupByWithoutValueFilterDataSet extends GroupByEngineDataSet { StringBuilder series = new StringBuilder(); for (long localCurStartTime = startTime; - localCurStartTime < endTime; + localCurStartTime + interval < endTime; // + interval to make the last bucket complete + // e.g, T=11,nout=3,interval=floor(11/3)=3, + // [0,3),[3,6),[6,9), no need incomplete [9,11) + // then the number of buckets must be Math.floor((endTime-startTime)/interval) localCurStartTime += interval) { // not change real curStartTime&curEndTime // attention the returned aggregations need deep copy if using directly List<AggregateResult> aggregations = @@ -289,14 +445,9 @@ public class GroupByWithoutValueFilterDataSet extends GroupByEngineDataSet { TsFileFilter fileFilter, boolean ascending) throws StorageEngineException, QueryProcessException { - if (CONFIG.getEnableTri().equals("MinMax")) { - // TODO + if (CONFIG.getEnableTri().equals("MinMax") || CONFIG.getEnableTri().equals("MinMaxLTTB")) { return new LocalGroupByExecutorTri_MinMax( path, allSensors, dataType, context, timeFilter, fileFilter, ascending); - } else if (CONFIG.getEnableTri().equals("MinMaxLTTB")) { - // TODO - return new LocalGroupByExecutor( - path, allSensors, dataType, context, timeFilter, fileFilter, ascending); } else if (CONFIG.getEnableTri().equals("M4LTTB")) { // TODO return new LocalGroupByExecutor( diff --git a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/LocalGroupByExecutorTri_MinMax.java b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/LocalGroupByExecutorTri_MinMax.java index ed4ced412ef..ec91aa29671 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/LocalGroupByExecutorTri_MinMax.java +++ b/server/src/main/java/org/apache/iotdb/db/query/dataset/groupby/LocalGroupByExecutorTri_MinMax.java @@ -333,9 +333,9 @@ public class LocalGroupByExecutorTri_MinMax implements GroupByExecutor { TSDataType dataType = chunkSuit4Tri.chunkMetadata.getDataType(); Object v; switch (dataType) { - case INT64: - v = valueBuffer.getLong(pageReader.timeBufferLength + i * 8); - break; + // case INT64: + // v = valueBuffer.getLong(pageReader.timeBufferLength + i * 8); + // break; case DOUBLE: v = valueBuffer.getDouble(pageReader.timeBufferLength + i * 8); break; diff --git a/server/src/test/java/org/apache/iotdb/db/integration/tri/MyTest_MinMax.java b/server/src/test/java/org/apache/iotdb/db/integration/tri/MyTest_MinMax.java index 8364c497ada..abb46b1b54d 100644 --- a/server/src/test/java/org/apache/iotdb/db/integration/tri/MyTest_MinMax.java +++ b/server/src/test/java/org/apache/iotdb/db/integration/tri/MyTest_MinMax.java @@ -48,14 +48,14 @@ public class MyTest_MinMax { * (1) Don't change the sequence of the above two aggregates * (2) Assume each chunk has only one page. * (3) Assume all chunks are sequential and no deletes. - * (4) Assume plain encoding, UNCOMPRESSED, Long or Double data type, no compaction + * (4) Assume plain encoding, UNCOMPRESSED, Double data type, no compaction */ private static final String TIMESTAMP_STR = "Time"; private static String[] creationSqls = new String[] { "SET STORAGE GROUP TO root.vehicle.d0", - "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT64, ENCODING=PLAIN", + "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=DOUBLE, ENCODING=PLAIN", // IoTDB int data type does not support plain encoding, so use long data type }; @@ -100,7 +100,7 @@ public class MyTest_MinMax { prepareData1(); // String[] res = new String[]{"0,1[20],15[2]", "25,8[25],8[25]", "50,3[54],3[54]", // "75,null,null"}; - String res = "0,1[20],15[2],8[25],8[25],3[54],3[54],null,null,"; + String res = "0,1.0[20],15.0[2],8.0[25],8.0[25],3.0[54],3.0[54],null,null,"; // 0,BPv[t]ofBucket1,TPv[t]ofBucket1,BPv[t]ofBucket2,TPv[t]ofBucket2,... try (Connection connection = DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root"); @@ -159,7 +159,7 @@ public class MyTest_MinMax { // String[] res = new String[]{"0,1[10],10[2]", "25,2[40],8[30]", "50,4[72],20[62]", // "75,1[90],11[80]"}; - String res = "0,1[10],10[2],2[40],8[30],4[72],20[62],1[90],11[80],"; + String res = "0,1.0[10],10.0[2],2.0[40],8.0[30],4.0[72],20.0[62],1.0[90],11.0[80],"; // 0,BPv[t]ofBucket1,TPv[t]ofBucket1,BPv[t]ofBucket2,TPv[t]ofBucket2,... try (Connection connection = DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root"); @@ -231,7 +231,7 @@ public class MyTest_MinMax { // String[] res = new String[]{"0,1[10],10[2]", "25,null,null", "50,4[72],20[62]", // "75,1[90],11[80]"}; - String res = "0,1[10],10[2],null,null,4[72],20[62],1[90],11[80],"; + String res = "0,1.0[10],10.0[2],null,null,4.0[72],20.0[62],1.0[90],11.0[80],"; // 0,BPv[t]ofBucket1,TPv[t]ofBucket1,BPv[t]ofBucket2,TPv[t]ofBucket2,... try (Connection connection = DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root"); diff --git a/server/src/test/java/org/apache/iotdb/db/integration/tri/MyTest_MinMax.java b/server/src/test/java/org/apache/iotdb/db/integration/tri/MyTest_MinMaxLTTB.java similarity index 80% copy from server/src/test/java/org/apache/iotdb/db/integration/tri/MyTest_MinMax.java copy to server/src/test/java/org/apache/iotdb/db/integration/tri/MyTest_MinMaxLTTB.java index 8364c497ada..e80a6c3f8cf 100644 --- a/server/src/test/java/org/apache/iotdb/db/integration/tri/MyTest_MinMax.java +++ b/server/src/test/java/org/apache/iotdb/db/integration/tri/MyTest_MinMaxLTTB.java @@ -40,7 +40,7 @@ import java.util.Locale; import static org.junit.Assert.fail; -public class MyTest_MinMax { +public class MyTest_MinMaxLTTB { /* * Sql format: SELECT min_value(s0), max_value(s0) ROM root.xx group by ([tqs,tqe),IntervalLength). @@ -55,25 +55,24 @@ public class MyTest_MinMax { private static String[] creationSqls = new String[] { "SET STORAGE GROUP TO root.vehicle.d0", - "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT64, ENCODING=PLAIN", + "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=DOUBLE, ENCODING=PLAIN", // IoTDB int data type does not support plain encoding, so use long data type }; private final String d0s0 = "root.vehicle.d0.s0"; private static final String insertTemplate = - "INSERT INTO root.vehicle.d0(timestamp,s0)" + " VALUES(%d,%d)"; + "INSERT INTO root.vehicle.d0(timestamp,s0)" + " VALUES(%d,%f)"; private static final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig(); @Before public void setUp() throws Exception { TSFileDescriptor.getInstance().getConfig().setTimeEncoder("PLAIN"); - // originalCompactionStrategy = config.getCompactionStrategy(); config.setTimestampPrecision("ms"); config.setCompactionStrategy(CompactionStrategy.NO_COMPACTION); - config.setEnableTri("MinMax"); + config.setEnableTri("MinMaxLTTB"); // 但是如果走的是unpackOneChunkMetaData(firstChunkMetadata)就没问题, // 因为它直接用chunk元数据去构造pageReader, @@ -92,16 +91,12 @@ public class MyTest_MinMax { @After public void tearDown() throws Exception { EnvironmentUtils.cleanEnv(); - // config.setCompactionStrategy(originalCompactionStrategy); } @Test public void test1() throws Exception { prepareData1(); - // String[] res = new String[]{"0,1[20],15[2]", "25,8[25],8[25]", "50,3[54],3[54]", - // "75,null,null"}; String res = "0,1[20],15[2],8[25],8[25],3[54],3[54],null,null,"; - // 0,BPv[t]ofBucket1,TPv[t]ofBucket1,BPv[t]ofBucket2,TPv[t]ofBucket2,... try (Connection connection = DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root"); Statement statement = connection.createStatement()) { @@ -140,12 +135,94 @@ public class MyTest_MinMax { statement.execute(sql); } - statement.execute(String.format(Locale.ENGLISH, insertTemplate, 1, 5)); - statement.execute(String.format(Locale.ENGLISH, insertTemplate, 2, 15)); - statement.execute(String.format(Locale.ENGLISH, insertTemplate, 20, 1)); - statement.execute(String.format(Locale.ENGLISH, insertTemplate, 25, 8)); - statement.execute(String.format(Locale.ENGLISH, insertTemplate, 54, 3)); - statement.execute(String.format(Locale.ENGLISH, insertTemplate, 120, 8)); + statement.execute(String.format(Locale.ENGLISH, insertTemplate, 1, 5.0)); + statement.execute(String.format(Locale.ENGLISH, insertTemplate, 2, 15.0)); + statement.execute(String.format(Locale.ENGLISH, insertTemplate, 20, 1.0)); + statement.execute(String.format(Locale.ENGLISH, insertTemplate, 25, 8.0)); + statement.execute(String.format(Locale.ENGLISH, insertTemplate, 54, 3.0)); + statement.execute(String.format(Locale.ENGLISH, insertTemplate, 120, 8.0)); + statement.execute("FLUSH"); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void test2() throws Exception { + prepareData2(); + String res = + "-1.2079272[0],1.101946[200],-1.014322[700],0.809559[1500],-0.785419[1600],-0.0211206[2100],"; + try (Connection connection = + DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root"); + Statement statement = connection.createStatement()) { + boolean hasResultSet = + statement.execute( + "SELECT min_value(s0), max_value(s0)" + + " FROM root.vehicle.d0 group by ([100,2100),250ms)"); + // rps=4,nout=6,minmaxInterval=floor((tn-t2)/((nout-2)*rps/2))=250ms + Assert.assertTrue(hasResultSet); + try (ResultSet resultSet = statement.getResultSet()) { + int i = 0; + while (resultSet.next()) { + // 注意从1开始编号,所以第一列是无意义时间戳 + String ans = resultSet.getString(2); + System.out.println(ans); + Assert.assertEquals(res, ans); + } + } + // System.out.println(((IoTDBStatement) statement).executeFinish()); + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + private static void prepareData2() { + // data: + // no overlap, no delete + try (Connection connection = + DriverManager.getConnection( + Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root"); + Statement statement = connection.createStatement()) { + + for (String sql : creationSqls) { + statement.execute(sql); + } + + int[] t = + new int[] { + 0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, + 1600, 1700, 1800, 1900, 2000, 2100 + }; + double[] v = + new double[] { + -1.2079272, + -0.01120245, + 1.1019456, + -0.52320362, + -0.35970289, + 0.1453591, + -0.45947892, + -1.0143219, + 0.81760821, + 0.5325646, + -0.29532424, + -0.1469335, + -0.12252526, + -0.67607713, + -0.16967308, + 0.8095585, + -0.78541944, + 0.03221141, + 0.31586886, + -0.41353356, + -0.21019539, + -0.0211206 + }; + for (int i = 0; i < t.length; i++) { + statement.execute(String.format(Locale.ENGLISH, insertTemplate, t[i], v[i])); + } statement.execute("FLUSH"); } catch (Exception e) { diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/IOMonitor2.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/IOMonitor2.java index c20a9de8994..c55ee561655 100644 --- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/IOMonitor2.java +++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/IOMonitor2.java @@ -256,6 +256,11 @@ public class IOMonitor2 { // M4_LSM_TP_SEARCH_ARRAY_c_genBPTP_cnt = 0; } + public static double calculateTri( + double t1, double v1, double t2, double v2, double t3, double v3) { + return Math.abs((t1 - t3) * (v2 - v3) - (t2 - t3) * (v1 - v3)) / 2; + } + public static void addMeasure(Operation operation, long elapsedTimeInNanosecond) { switch (operation) { case DCP_Server_Query_Execute:
