You are viewing a plain text version of this content. The canonical link for it is here.
Posted to reviews@iotdb.apache.org by GitBox <gi...@apache.org> on 2021/09/08 15:33:54 UTC

[GitHub] [iotdb] LebronAl commented on a change in pull request #3879: [IOTDB-1484]Auto create schema functionality with e2e testing in cluster

LebronAl commented on a change in pull request #3879:
URL: https://github.com/apache/iotdb/pull/3879#discussion_r704242634



##########
File path: testcontainer/src/test/java/org/apache/iotdb/db/sql/Cases.java
##########
@@ -610,4 +614,222 @@ public void SetSystemReadOnlyWritableTest() throws SQLException {
 
     writeStatement.execute(setWritable);
   }
+
+  @Test
+  public void testAutoCreateSchemaInClusterMode()
+      throws IoTDBConnectionException, StatementExecutionException, SQLException {
+    session.setEnableCacheLeader(false);
+    List<String> measurement_list = new ArrayList<>();
+    measurement_list.add("s1");
+    measurement_list.add("s2");
+    measurement_list.add("s3");
+
+    List<TSDataType> type_list = new ArrayList<>();

Review comment:
       Since all APIs are using camel case nomenclature, you'd better keep consistent

##########
File path: testcontainer/src/test/java/org/apache/iotdb/db/sql/Cases.java
##########
@@ -610,4 +614,222 @@ public void SetSystemReadOnlyWritableTest() throws SQLException {
 
     writeStatement.execute(setWritable);
   }
+
+  @Test
+  public void testAutoCreateSchemaInClusterMode()
+      throws IoTDBConnectionException, StatementExecutionException, SQLException {
+    session.setEnableCacheLeader(false);

Review comment:
       You'd better disable the CacheLeader directly in the E2E module, not just in this test. I will recommend that you use the Session.Builder method to create session instead of adding setup methods.

##########
File path: testcontainer/src/test/java/org/apache/iotdb/db/sql/Cases.java
##########
@@ -610,4 +614,222 @@ public void SetSystemReadOnlyWritableTest() throws SQLException {
 
     writeStatement.execute(setWritable);
   }
+
+  @Test
+  public void testAutoCreateSchemaInClusterMode()
+      throws IoTDBConnectionException, StatementExecutionException, SQLException {
+    session.setEnableCacheLeader(false);
+    List<String> measurement_list = new ArrayList<>();
+    measurement_list.add("s1");
+    measurement_list.add("s2");
+    measurement_list.add("s3");
+
+    List<TSDataType> type_list = new ArrayList<>();
+    type_list.add(TSDataType.INT64);
+    type_list.add(TSDataType.INT64);
+    type_list.add(TSDataType.INT64);
+
+    List<Object> value_list = new ArrayList<>();
+    value_list.add(1L);
+    value_list.add(2L);
+    value_list.add(3L);
+
+    for (int i = 0; i < 5; i++) {
+      String sg = "root.sg" + String.valueOf(i);
+      session.setStorageGroup(sg);
+      for (int j = 0; j < 10; j++) {
+        session.createTimeseries(
+            String.format("%s.d1.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+        session.createTimeseries(
+            String.format("%s.d2.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+        session.createTimeseries(
+            String.format("%s.d3.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+        session.createTimeseries(
+            String.format("%s.d4.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+      }
+    }
+
+    // step 1: insert into existing time series.
+    for (int i = 0; i < 5; i++) {
+      for (long t = 0; t < 3; t++) {
+        session.insertRecord(
+            String.format("root.sg%s.d1", i), t, measurement_list, type_list, 1L, 2L, 3L);
+      }
+    }
+
+    List<List<String>> measurements_list = new ArrayList<>();
+    List<List<Object>> values_list = new ArrayList<>();
+    List<List<TSDataType>> types_List = new ArrayList<>();
+    List<String> device_list = new ArrayList<>();
+    for (int i = 0; i < 5; i++) {
+      String device_path = String.format("root.sg%s.d2", i);
+      device_list.add(device_path);
+      types_List.add(type_list);
+      measurements_list.add(measurement_list);
+      values_list.add(value_list);
+    }
+
+    for (long t = 0; t < 3; t++) {
+      List<Long> time_list = new ArrayList<>();

Review comment:
       Why doing same work 5 times?

##########
File path: testcontainer/src/test/java/org/apache/iotdb/db/sql/Cases.java
##########
@@ -610,4 +614,222 @@ public void SetSystemReadOnlyWritableTest() throws SQLException {
 
     writeStatement.execute(setWritable);
   }
+
+  @Test
+  public void testAutoCreateSchemaInClusterMode()
+      throws IoTDBConnectionException, StatementExecutionException, SQLException {
+    session.setEnableCacheLeader(false);
+    List<String> measurement_list = new ArrayList<>();
+    measurement_list.add("s1");
+    measurement_list.add("s2");
+    measurement_list.add("s3");
+
+    List<TSDataType> type_list = new ArrayList<>();
+    type_list.add(TSDataType.INT64);
+    type_list.add(TSDataType.INT64);
+    type_list.add(TSDataType.INT64);
+
+    List<Object> value_list = new ArrayList<>();
+    value_list.add(1L);
+    value_list.add(2L);
+    value_list.add(3L);
+
+    for (int i = 0; i < 5; i++) {
+      String sg = "root.sg" + String.valueOf(i);
+      session.setStorageGroup(sg);
+      for (int j = 0; j < 10; j++) {
+        session.createTimeseries(
+            String.format("%s.d1.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+        session.createTimeseries(
+            String.format("%s.d2.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+        session.createTimeseries(
+            String.format("%s.d3.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+        session.createTimeseries(
+            String.format("%s.d4.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+      }
+    }
+
+    // step 1: insert into existing time series.
+    for (int i = 0; i < 5; i++) {
+      for (long t = 0; t < 3; t++) {
+        session.insertRecord(
+            String.format("root.sg%s.d1", i), t, measurement_list, type_list, 1L, 2L, 3L);
+      }
+    }
+
+    List<List<String>> measurements_list = new ArrayList<>();
+    List<List<Object>> values_list = new ArrayList<>();
+    List<List<TSDataType>> types_List = new ArrayList<>();
+    List<String> device_list = new ArrayList<>();
+    for (int i = 0; i < 5; i++) {
+      String device_path = String.format("root.sg%s.d2", i);
+      device_list.add(device_path);
+      types_List.add(type_list);
+      measurements_list.add(measurement_list);
+      values_list.add(value_list);
+    }
+
+    for (long t = 0; t < 3; t++) {
+      List<Long> time_list = new ArrayList<>();
+      for (int i = 0; i < 5; i++) {
+        time_list.add(t);
+      }
+      session.insertRecords(device_list, time_list, measurements_list, types_List, values_list);
+    }
+
+    List<IMeasurementSchema> schemaList = new ArrayList<>();
+    schemaList.add(new MeasurementSchema("s1", TSDataType.INT64));
+    schemaList.add(new MeasurementSchema("s2", TSDataType.INT64));
+    schemaList.add(new MeasurementSchema("s3", TSDataType.INT64));
+
+    Map<String, Tablet> tabletMap = new HashMap<>();
+    for (int i = 0; i < 5; i++) {
+      Tablet tablet = new Tablet(String.format("root.sg%s.d3", i), schemaList, 10);
+      for (long row = 0; row < 3; row++) {
+        int rowIndex = tablet.rowSize++;
+        tablet.addTimestamp(rowIndex, row);
+        tablet.addValue("s1", rowIndex, 1L);
+        tablet.addValue("s2", rowIndex, 2L);
+        tablet.addValue("s3", rowIndex, 3L);
+      }
+      session.insertTablet(tablet);
+      tablet.setPrefixPath(String.format("root.sg%s.d4", i));
+      tabletMap.put(String.format("root.sg%s.d4", i), tablet);
+    }
+
+    session.insertTablets(tabletMap);
+
+    // step 2: test auto create sg and time series schema
+    for (int i = 5; i < 10; i++) {
+      for (long t = 0; t < 3; t++) {
+        session.insertRecord(
+            String.format("root.sg%s.d1", i), t, measurement_list, type_list, 1L, 2L, 3L);
+      }
+    }
+
+    device_list.clear();
+    for (int i = 5; i < 10; i++) {
+      String device_path = String.format("root.sg%s.d2", i);
+      device_list.add(device_path);
+    }
+
+    for (long t = 0; t < 3; t++) {
+      List<Long> time_list = new ArrayList<>();
+      for (int i = 0; i < 5; i++) {
+        time_list.add(t);
+      }
+      session.insertRecords(device_list, time_list, measurements_list, types_List, values_list);
+    }
+
+    tabletMap.clear();
+    for (int i = 5; i < 10; i++) {
+      Tablet tablet = new Tablet(String.format("root.sg%s.d3", i), schemaList, 10);
+      for (long row = 0; row < 3; row++) {
+        int rowIndex = tablet.rowSize++;
+        tablet.addTimestamp(rowIndex, row);
+        tablet.addValue("s1", rowIndex, 1L);
+        tablet.addValue("s2", rowIndex, 2L);
+        tablet.addValue("s3", rowIndex, 3L);
+      }
+      session.insertTablet(tablet);
+      tablet.setPrefixPath(String.format("root.sg%s.d4", i));
+      tabletMap.put(String.format("root.sg%s.d4", i), tablet);
+    }
+
+    session.insertTablets(tabletMap);
+
+    for (Statement readStatement : readStatements) {
+      for (int i = 0; i < 10; i++) {
+        for (int d = 1; d <= 4; d++) {
+          ResultSet resultSet =
+              readStatement.executeQuery(String.format("SELECT s1,s2,s3 from root.sg%s.d%s", i, d));
+          for (long t = 0; t < 3; t++) {
+            Assert.assertTrue(resultSet.next());
+            Assert.assertEquals(resultSet.getLong(1), t);
+            Assert.assertEquals(resultSet.getString(2), "1");
+            Assert.assertEquals(resultSet.getString(3), "2");
+            Assert.assertEquals(resultSet.getString(4), "3");
+          }
+        }
+      }
+    }
+
+    // test create time series without sg
+    for (int i = 0; i < 5; i++) {
+      session.createTimeseries(
+          String.format("root.sg1%s.d1.s1", i),
+          TSDataType.INT64,
+          TSEncoding.RLE,
+          CompressionType.SNAPPY);
+    }
+
+    List<String> path = new ArrayList<>();
+    List<TSDataType> dataTypes = new ArrayList<>();
+    List<TSEncoding> encodings = new ArrayList<>();
+    List<CompressionType> compressionTypes = new ArrayList<>();
+    for (int i = 5; i < 10; i++) {
+      path.add(String.format("root.sg1%s.d1.s1", i));
+      dataTypes.add(TSDataType.INT64);
+      encodings.add(TSEncoding.RLE);
+      compressionTypes.add(CompressionType.SNAPPY);
+    }
+    session.createMultiTimeseries(
+        path, dataTypes, encodings, compressionTypes, null, null, null, null);
+    for (Statement readStatement : readStatements) {
+      for (int i = 0; i < 10; i++) {
+        ResultSet resultSet =
+            readStatement.executeQuery(String.format("show timeseries root.sg1%s.d1.s1", i));
+        Assert.assertTrue(resultSet.next());
+      }
+    }
+
+    // other insert cases
+    List<Long> time_list = new ArrayList<>();
+    List<List<String>> measurementsList = new ArrayList<>();
+    for (int i = 0; i < 5; i++) {
+      time_list.add((long) i);
+      List<String> measurements = new ArrayList<>();
+      measurements.add(String.format("s%d", i));
+      measurements.add(String.format("s%d", i + 5));
+      measurements.add(String.format("s%d", i + 10));
+      measurementsList.add(measurements);
+    }
+    session.insertRecordsOfOneDevice(

Review comment:
       Why don't you put them in front like all the others?

##########
File path: testcontainer/src/test/java/org/apache/iotdb/db/sql/Cases.java
##########
@@ -610,4 +614,222 @@ public void SetSystemReadOnlyWritableTest() throws SQLException {
 
     writeStatement.execute(setWritable);
   }
+
+  @Test
+  public void testAutoCreateSchemaInClusterMode()
+      throws IoTDBConnectionException, StatementExecutionException, SQLException {
+    session.setEnableCacheLeader(false);
+    List<String> measurement_list = new ArrayList<>();
+    measurement_list.add("s1");
+    measurement_list.add("s2");
+    measurement_list.add("s3");
+
+    List<TSDataType> type_list = new ArrayList<>();
+    type_list.add(TSDataType.INT64);
+    type_list.add(TSDataType.INT64);
+    type_list.add(TSDataType.INT64);
+
+    List<Object> value_list = new ArrayList<>();
+    value_list.add(1L);
+    value_list.add(2L);
+    value_list.add(3L);
+
+    for (int i = 0; i < 5; i++) {
+      String sg = "root.sg" + String.valueOf(i);
+      session.setStorageGroup(sg);
+      for (int j = 0; j < 10; j++) {
+        session.createTimeseries(
+            String.format("%s.d1.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+        session.createTimeseries(
+            String.format("%s.d2.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+        session.createTimeseries(
+            String.format("%s.d3.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+        session.createTimeseries(
+            String.format("%s.d4.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+      }
+    }
+
+    // step 1: insert into existing time series.
+    for (int i = 0; i < 5; i++) {
+      for (long t = 0; t < 3; t++) {
+        session.insertRecord(
+            String.format("root.sg%s.d1", i), t, measurement_list, type_list, 1L, 2L, 3L);
+      }
+    }
+
+    List<List<String>> measurements_list = new ArrayList<>();
+    List<List<Object>> values_list = new ArrayList<>();
+    List<List<TSDataType>> types_List = new ArrayList<>();
+    List<String> device_list = new ArrayList<>();
+    for (int i = 0; i < 5; i++) {
+      String device_path = String.format("root.sg%s.d2", i);
+      device_list.add(device_path);
+      types_List.add(type_list);
+      measurements_list.add(measurement_list);
+      values_list.add(value_list);
+    }
+
+    for (long t = 0; t < 3; t++) {
+      List<Long> time_list = new ArrayList<>();
+      for (int i = 0; i < 5; i++) {
+        time_list.add(t);
+      }
+      session.insertRecords(device_list, time_list, measurements_list, types_List, values_list);
+    }
+
+    List<IMeasurementSchema> schemaList = new ArrayList<>();
+    schemaList.add(new MeasurementSchema("s1", TSDataType.INT64));
+    schemaList.add(new MeasurementSchema("s2", TSDataType.INT64));
+    schemaList.add(new MeasurementSchema("s3", TSDataType.INT64));
+
+    Map<String, Tablet> tabletMap = new HashMap<>();
+    for (int i = 0; i < 5; i++) {
+      Tablet tablet = new Tablet(String.format("root.sg%s.d3", i), schemaList, 10);
+      for (long row = 0; row < 3; row++) {
+        int rowIndex = tablet.rowSize++;
+        tablet.addTimestamp(rowIndex, row);
+        tablet.addValue("s1", rowIndex, 1L);
+        tablet.addValue("s2", rowIndex, 2L);
+        tablet.addValue("s3", rowIndex, 3L);
+      }
+      session.insertTablet(tablet);
+      tablet.setPrefixPath(String.format("root.sg%s.d4", i));
+      tabletMap.put(String.format("root.sg%s.d4", i), tablet);
+    }
+
+    session.insertTablets(tabletMap);
+
+    // step 2: test auto create sg and time series schema
+    for (int i = 5; i < 10; i++) {
+      for (long t = 0; t < 3; t++) {
+        session.insertRecord(
+            String.format("root.sg%s.d1", i), t, measurement_list, type_list, 1L, 2L, 3L);
+      }
+    }
+
+    device_list.clear();
+    for (int i = 5; i < 10; i++) {
+      String device_path = String.format("root.sg%s.d2", i);
+      device_list.add(device_path);
+    }
+
+    for (long t = 0; t < 3; t++) {
+      List<Long> time_list = new ArrayList<>();
+      for (int i = 0; i < 5; i++) {
+        time_list.add(t);
+      }
+      session.insertRecords(device_list, time_list, measurements_list, types_List, values_list);
+    }
+
+    tabletMap.clear();
+    for (int i = 5; i < 10; i++) {
+      Tablet tablet = new Tablet(String.format("root.sg%s.d3", i), schemaList, 10);
+      for (long row = 0; row < 3; row++) {
+        int rowIndex = tablet.rowSize++;
+        tablet.addTimestamp(rowIndex, row);
+        tablet.addValue("s1", rowIndex, 1L);
+        tablet.addValue("s2", rowIndex, 2L);
+        tablet.addValue("s3", rowIndex, 3L);
+      }
+      session.insertTablet(tablet);
+      tablet.setPrefixPath(String.format("root.sg%s.d4", i));
+      tabletMap.put(String.format("root.sg%s.d4", i), tablet);
+    }
+
+    session.insertTablets(tabletMap);
+
+    for (Statement readStatement : readStatements) {
+      for (int i = 0; i < 10; i++) {
+        for (int d = 1; d <= 4; d++) {
+          ResultSet resultSet =
+              readStatement.executeQuery(String.format("SELECT s1,s2,s3 from root.sg%s.d%s", i, d));
+          for (long t = 0; t < 3; t++) {
+            Assert.assertTrue(resultSet.next());
+            Assert.assertEquals(resultSet.getLong(1), t);
+            Assert.assertEquals(resultSet.getString(2), "1");
+            Assert.assertEquals(resultSet.getString(3), "2");
+            Assert.assertEquals(resultSet.getString(4), "3");
+          }
+        }
+      }
+    }
+
+    // test create time series without sg

Review comment:
       test create time series with sg

##########
File path: testcontainer/src/test/java/org/apache/iotdb/db/sql/Cases.java
##########
@@ -610,4 +614,222 @@ public void SetSystemReadOnlyWritableTest() throws SQLException {
 
     writeStatement.execute(setWritable);
   }
+
+  @Test
+  public void testAutoCreateSchemaInClusterMode()
+      throws IoTDBConnectionException, StatementExecutionException, SQLException {
+    session.setEnableCacheLeader(false);
+    List<String> measurement_list = new ArrayList<>();
+    measurement_list.add("s1");
+    measurement_list.add("s2");
+    measurement_list.add("s3");
+
+    List<TSDataType> type_list = new ArrayList<>();
+    type_list.add(TSDataType.INT64);
+    type_list.add(TSDataType.INT64);
+    type_list.add(TSDataType.INT64);
+
+    List<Object> value_list = new ArrayList<>();
+    value_list.add(1L);
+    value_list.add(2L);
+    value_list.add(3L);
+
+    for (int i = 0; i < 5; i++) {
+      String sg = "root.sg" + String.valueOf(i);
+      session.setStorageGroup(sg);
+      for (int j = 0; j < 10; j++) {
+        session.createTimeseries(
+            String.format("%s.d1.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+        session.createTimeseries(
+            String.format("%s.d2.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+        session.createTimeseries(
+            String.format("%s.d3.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+        session.createTimeseries(
+            String.format("%s.d4.s%s", sg, j),
+            TSDataType.INT64,
+            TSEncoding.RLE,
+            CompressionType.SNAPPY);
+      }
+    }
+
+    // step 1: insert into existing time series.
+    for (int i = 0; i < 5; i++) {
+      for (long t = 0; t < 3; t++) {
+        session.insertRecord(
+            String.format("root.sg%s.d1", i), t, measurement_list, type_list, 1L, 2L, 3L);
+      }
+    }
+
+    List<List<String>> measurements_list = new ArrayList<>();
+    List<List<Object>> values_list = new ArrayList<>();
+    List<List<TSDataType>> types_List = new ArrayList<>();
+    List<String> device_list = new ArrayList<>();
+    for (int i = 0; i < 5; i++) {
+      String device_path = String.format("root.sg%s.d2", i);
+      device_list.add(device_path);
+      types_List.add(type_list);
+      measurements_list.add(measurement_list);
+      values_list.add(value_list);
+    }
+
+    for (long t = 0; t < 3; t++) {
+      List<Long> time_list = new ArrayList<>();
+      for (int i = 0; i < 5; i++) {
+        time_list.add(t);
+      }
+      session.insertRecords(device_list, time_list, measurements_list, types_List, values_list);
+    }
+
+    List<IMeasurementSchema> schemaList = new ArrayList<>();
+    schemaList.add(new MeasurementSchema("s1", TSDataType.INT64));
+    schemaList.add(new MeasurementSchema("s2", TSDataType.INT64));
+    schemaList.add(new MeasurementSchema("s3", TSDataType.INT64));
+
+    Map<String, Tablet> tabletMap = new HashMap<>();
+    for (int i = 0; i < 5; i++) {
+      Tablet tablet = new Tablet(String.format("root.sg%s.d3", i), schemaList, 10);
+      for (long row = 0; row < 3; row++) {
+        int rowIndex = tablet.rowSize++;
+        tablet.addTimestamp(rowIndex, row);
+        tablet.addValue("s1", rowIndex, 1L);
+        tablet.addValue("s2", rowIndex, 2L);
+        tablet.addValue("s3", rowIndex, 3L);
+      }
+      session.insertTablet(tablet);
+      tablet.setPrefixPath(String.format("root.sg%s.d4", i));
+      tabletMap.put(String.format("root.sg%s.d4", i), tablet);
+    }
+
+    session.insertTablets(tabletMap);
+
+    // step 2: test auto create sg and time series schema
+    for (int i = 5; i < 10; i++) {
+      for (long t = 0; t < 3; t++) {
+        session.insertRecord(
+            String.format("root.sg%s.d1", i), t, measurement_list, type_list, 1L, 2L, 3L);
+      }
+    }
+
+    device_list.clear();
+    for (int i = 5; i < 10; i++) {
+      String device_path = String.format("root.sg%s.d2", i);
+      device_list.add(device_path);
+    }
+
+    for (long t = 0; t < 3; t++) {
+      List<Long> time_list = new ArrayList<>();
+      for (int i = 0; i < 5; i++) {
+        time_list.add(t);
+      }
+      session.insertRecords(device_list, time_list, measurements_list, types_List, values_list);
+    }
+
+    tabletMap.clear();
+    for (int i = 5; i < 10; i++) {
+      Tablet tablet = new Tablet(String.format("root.sg%s.d3", i), schemaList, 10);
+      for (long row = 0; row < 3; row++) {
+        int rowIndex = tablet.rowSize++;
+        tablet.addTimestamp(rowIndex, row);
+        tablet.addValue("s1", rowIndex, 1L);
+        tablet.addValue("s2", rowIndex, 2L);
+        tablet.addValue("s3", rowIndex, 3L);
+      }
+      session.insertTablet(tablet);
+      tablet.setPrefixPath(String.format("root.sg%s.d4", i));
+      tabletMap.put(String.format("root.sg%s.d4", i), tablet);
+    }
+
+    session.insertTablets(tabletMap);
+

Review comment:
       where are the cases that sg exists but device does not exist?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@iotdb.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org