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

nehapawar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new 9929dad  Adding more table config validation (#6073)
9929dad is described below

commit 9929dad2e804f525b8ace925e859e07c6fdee9da
Author: icefury71 <chinmay.cere...@gmail.com>
AuthorDate: Fri Oct 2 09:41:55 2020 -0700

    Adding more table config validation (#6073)
    
    Adding more table config validation (retention, pushType and tenant)
    Fixing bug where retention manager does not work for real-time tables if 
the pushType is missing.
---
 .../api/resources/PinotTableRestletResource.java   |  2 +-
 .../helix/core/PinotHelixResourceManager.java      | 28 ++++++++-----
 .../helix/core/retention/RetentionManager.java     |  5 ++-
 .../apache/pinot/core/util/TableConfigUtils.java   | 48 +++++++++++++++++++++-
 .../pinot/core/util/TableConfigUtilsTest.java      | 25 +++++++++++
 5 files changed, 93 insertions(+), 15 deletions(-)

diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotTableRestletResource.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotTableRestletResource.java
index 7060d00..c5da9e1 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotTableRestletResource.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotTableRestletResource.java
@@ -151,7 +151,7 @@ public class PinotTableRestletResource {
   public String recommendConfig(String inputStr) {
     try {
       return RecommenderDriver.run(inputStr);
-    }catch (Exception e){
+    } catch (Exception e) {
       throw new ControllerApplicationException(LOGGER, e.getMessage(), 
Response.Status.BAD_REQUEST, e);
     }
   }
diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/PinotHelixResourceManager.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/PinotHelixResourceManager.java
index af8c3be..0cc0a34 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/PinotHelixResourceManager.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/PinotHelixResourceManager.java
@@ -1095,16 +1095,7 @@ public class PinotHelixResourceManager {
    */
   public void addTable(TableConfig tableConfig)
       throws IOException {
-    TenantConfig tenantConfig = tableConfig.getTenantConfig();
-    String brokerTag = tenantConfig.getBroker();
-    String serverTag = tenantConfig.getServer();
-    if (brokerTag == null || serverTag == null) {
-      String newBrokerTag = brokerTag == null ? 
TagNameUtils.DEFAULT_TENANT_NAME : brokerTag;
-      String newServerTag = serverTag == null ? 
TagNameUtils.DEFAULT_TENANT_NAME : serverTag;
-      tableConfig.setTenantConfig(new TenantConfig(newBrokerTag, newServerTag, 
tenantConfig.getTagOverrideConfig()));
-    }
     validateTableTenantConfig(tableConfig);
-
     String tableNameWithType = tableConfig.getTableName();
     SegmentsValidationAndRetentionConfig segmentsConfig = 
tableConfig.getValidationConfig();
 
@@ -1191,12 +1182,27 @@ public class PinotHelixResourceManager {
   }
 
   /**
-   * Validates the tenant config for the table
+   * Validates the tenant config for the table. In case of a single tenant 
cluster,
+   * if the server and broker tenants are not specified in the config, they're
+   * auto-populated with the default tenant name. In case of a multi-tenant 
cluster,
+   * these parameters must be specified in the table config.
    */
   @VisibleForTesting
   void validateTableTenantConfig(TableConfig tableConfig) {
-    String tableNameWithType = tableConfig.getTableName();
     TenantConfig tenantConfig = tableConfig.getTenantConfig();
+    String tableNameWithType = tableConfig.getTableName();
+    String brokerTag = tenantConfig.getBroker();
+    String serverTag = tenantConfig.getServer();
+    if (brokerTag == null || serverTag == null) {
+      if (!_isSingleTenantCluster) {
+        throw new InvalidTableConfigException(
+            "server and broker tenants must be specified for multi-tenant 
cluster for table: " + tableNameWithType);
+      }
+
+      String newBrokerTag = brokerTag == null ? 
TagNameUtils.DEFAULT_TENANT_NAME : brokerTag;
+      String newServerTag = serverTag == null ? 
TagNameUtils.DEFAULT_TENANT_NAME : serverTag;
+      tableConfig.setTenantConfig(new TenantConfig(newBrokerTag, newServerTag, 
tenantConfig.getTagOverrideConfig()));
+    }
 
     // Check if tenant exists before creating the table
     Set<String> tagsToCheck = new TreeSet<>();
diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/retention/RetentionManager.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/retention/RetentionManager.java
index c074af8..2793087 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/retention/RetentionManager.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/retention/RetentionManager.java
@@ -44,6 +44,7 @@ import 
org.apache.pinot.controller.helix.core.retention.strategy.RetentionStrate
 import 
org.apache.pinot.controller.helix.core.retention.strategy.TimeRetentionStrategy;
 import org.apache.pinot.spi.config.table.SegmentsValidationAndRetentionConfig;
 import org.apache.pinot.spi.config.table.TableConfig;
+import org.apache.pinot.spi.config.table.TableType;
 import org.apache.pinot.spi.utils.builder.TableNameBuilder;
 import org.apache.pinot.spi.utils.retry.RetryPolicies;
 import org.apache.pinot.spi.utils.retry.RetryPolicy;
@@ -96,9 +97,11 @@ public class RetentionManager extends 
ControllerPeriodicTask<Void> {
       LOGGER.error("Failed to get table config for table: {}", 
tableNameWithType);
       return;
     }
+
+    // For offline tables, ensure that the segmentPushType is APPEND.
     SegmentsValidationAndRetentionConfig validationConfig = 
tableConfig.getValidationConfig();
     String segmentPushType = validationConfig.getSegmentPushType();
-    if (!"APPEND".equalsIgnoreCase(segmentPushType)) {
+    if (tableConfig.getTableType() == TableType.OFFLINE && 
!"APPEND".equalsIgnoreCase(segmentPushType)) {
       LOGGER.info("Segment push type is not APPEND for table: {}, skip", 
tableNameWithType);
       return;
     }
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/util/TableConfigUtils.java 
b/pinot-core/src/main/java/org/apache/pinot/core/util/TableConfigUtils.java
index caa32d5..bc23bb9 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/util/TableConfigUtils.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/util/TableConfigUtils.java
@@ -25,6 +25,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 import javax.annotation.Nullable;
 import org.apache.pinot.common.tier.TierFactory;
 import org.apache.pinot.common.utils.CommonConstants;
@@ -39,6 +40,7 @@ import 
org.apache.pinot.spi.config.table.SegmentsValidationAndRetentionConfig;
 import org.apache.pinot.spi.config.table.StarTreeIndexConfig;
 import org.apache.pinot.spi.config.table.TableConfig;
 import org.apache.pinot.spi.config.table.TableType;
+import org.apache.pinot.spi.config.table.TenantConfig;
 import org.apache.pinot.spi.config.table.TierConfig;
 import org.apache.pinot.spi.config.table.ingestion.FilterConfig;
 import org.apache.pinot.spi.config.table.ingestion.TransformConfig;
@@ -62,6 +64,7 @@ public final class TableConfigUtils {
    * 2. IngestionConfig
    * 3. TierConfigs
    * 4. Indexing config
+   * 5. Field Config List
    *
    * TODO: Add more validations for each section (e.g. validate conditions are 
met for aggregateMetrics)
    */
@@ -79,7 +82,7 @@ public final class TableConfigUtils {
   /**
    * Validates the table name with the following rules:
    * <ul>
-   *   <li>Table name shouldn't contain dot in it</li>
+   *   <li>Table name shouldn't contain dot or space in it</li>
    * </ul>
    */
   public static void validateTableName(TableConfig tableConfig) {
@@ -90,13 +93,52 @@ public final class TableConfigUtils {
   }
 
   /**
+   * Validates retention config. Checks for following things:
+   * - Valid segmentPushType
+   * - Valid retentionTimeUnit
+   */
+  public static void validateRetentionConfig(TableConfig tableConfig) {
+    SegmentsValidationAndRetentionConfig segmentsConfig = 
tableConfig.getValidationConfig();
+    String tableName = tableConfig.getTableName();
+
+    if (segmentsConfig == null) {
+      throw new IllegalStateException(
+          String.format("Table: %s, \"segmentsConfig\" field is missing in 
table config", tableName));
+    }
+
+    String segmentPushType = segmentsConfig.getSegmentPushType();
+    // segmentPushType is not needed for Realtime table
+    if (tableConfig.getTableType() == TableType.OFFLINE) {
+      if (segmentPushType == null) {
+        throw new IllegalStateException(String.format("Table: %s, null push 
type", tableName));
+      }
+
+      if (!segmentPushType.equalsIgnoreCase("REFRESH") && 
!segmentPushType.equalsIgnoreCase("APPEND")) {
+        throw new IllegalStateException(String.format("Table: %s, invalid push 
type: %s", tableName, segmentPushType));
+      }
+    }
+
+    // Retention may not be specified. Ignore validation in that case.
+    String timeUnitString = segmentsConfig.getRetentionTimeUnit();
+    if (timeUnitString == null || timeUnitString.isEmpty()) {
+      return;
+    }
+    try {
+      TimeUnit.valueOf(timeUnitString.toUpperCase());
+    } catch (Exception e) {
+      throw new IllegalStateException(String.format("Table: %s, invalid time 
unit: %s", tableName, timeUnitString));
+    }
+  }
+
+  /**
    * Validates the following in the validationConfig of the table
    * 1. For REALTIME table
    * - checks for non-null timeColumnName
    * - checks for valid field spec for timeColumnName in schema
+   * - Validates retention config
    *
    * 2. For OFFLINE table
-   * - checks for valid field spec for timeColumnName in schema, if 
timeColumnName and schema re non-null
+   * - checks for valid field spec for timeColumnName in schema, if 
timeColumnName and schema are non-null
    *
    * 3. Checks peerDownloadSchema
    */
@@ -122,6 +164,8 @@ public final class TableConfigUtils {
             + "' for peerSegmentDownloadScheme. Must be one of http or https");
       }
     }
+
+    validateRetentionConfig(tableConfig);
   }
 
   /**
diff --git 
a/pinot-core/src/test/java/org/apache/pinot/core/util/TableConfigUtilsTest.java 
b/pinot-core/src/test/java/org/apache/pinot/core/util/TableConfigUtilsTest.java
index de2493b..73a12e4 100644
--- 
a/pinot-core/src/test/java/org/apache/pinot/core/util/TableConfigUtilsTest.java
+++ 
b/pinot-core/src/test/java/org/apache/pinot/core/util/TableConfigUtilsTest.java
@@ -24,6 +24,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 import org.apache.pinot.common.tier.TierFactory;
 import org.apache.pinot.spi.config.table.ColumnPartitionConfig;
 import org.apache.pinot.spi.config.table.FieldConfig;
@@ -40,6 +41,7 @@ import org.apache.pinot.spi.data.Schema;
 import org.apache.pinot.spi.utils.builder.TableConfigBuilder;
 import org.testng.Assert;
 import org.testng.annotations.Test;
+import org.testng.collections.Sets;
 
 
 /**
@@ -635,4 +637,27 @@ public class TableConfigUtilsTest {
       // expected
     }
   }
+
+  @Test
+  public void testValidateRetentionConfig() {
+    Schema schema =
+        new 
Schema.SchemaBuilder().setSchemaName(TABLE_NAME).addSingleValueDimension("myCol",
 FieldSpec.DataType.STRING)
+            .build();
+    TableConfig tableConfig =
+        new 
TableConfigBuilder(TableType.OFFLINE).setTableName(TABLE_NAME).setRetentionTimeUnit("hours")
+            .setRetentionTimeValue("24").build();
+    try {
+      TableConfigUtils.validate(tableConfig, schema);
+    } catch (Exception e) {
+      Assert.fail("Should not fail for valid retention time unit value");
+    }
+
+    tableConfig = new 
TableConfigBuilder(TableType.OFFLINE).setTableName(TABLE_NAME).setRetentionTimeUnit("abc").build();
+    try {
+      TableConfigUtils.validate(tableConfig, schema);
+      Assert.fail("Should fail for invalid retention time unit value");
+    } catch (Exception e) {
+      // expected
+    }
+  }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org
For additional commands, e-mail: commits-h...@pinot.apache.org

Reply via email to