This is an automated email from the ASF dual-hosted git repository.
jackie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push:
new cba670fa4f Fallback for bad values in periodic controller task
configurations (#15466)
cba670fa4f is described below
commit cba670fa4fcd9a82fb6155563b9ea25ff0ad668b
Author: ayesheepatra07 <[email protected]>
AuthorDate: Tue May 6 16:13:53 2025 -0700
Fallback for bad values in periodic controller task configurations (#15466)
---
.../apache/pinot/controller/ControllerConf.java | 62 ++++++++++++++++++++--
.../api/resources/PinotControllerHealthCheck.java | 16 ++++++
.../pinot/controller/ControllerConfTest.java | 22 ++++++--
3 files changed, 92 insertions(+), 8 deletions(-)
diff --git
a/pinot-controller/src/main/java/org/apache/pinot/controller/ControllerConf.java
b/pinot-controller/src/main/java/org/apache/pinot/controller/ControllerConf.java
index d405c4dcf0..55728b0fc9 100644
---
a/pinot-controller/src/main/java/org/apache/pinot/controller/ControllerConf.java
+++
b/pinot-controller/src/main/java/org/apache/pinot/controller/ControllerConf.java
@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.lang3.StringUtils;
@@ -376,6 +377,8 @@ public class ControllerConf extends PinotConfiguration {
public static final String EXIT_ON_SCHEMA_CHECK_FAILURE =
"controller.startup.exitOnSchemaCheckFailure";
public static final boolean DEFAULT_EXIT_ON_SCHEMA_CHECK_FAILURE = true;
+ private final Map<String, String> _invalidConfigs = new
ConcurrentHashMap<>();
+
public ControllerConf() {
super(new HashMap<>());
}
@@ -602,6 +605,8 @@ public class ControllerConf extends PinotConfiguration {
public int getRetentionControllerFrequencyInSeconds() {
return
Optional.ofNullable(getProperty(ControllerPeriodicTasksConf.RETENTION_MANAGER_FREQUENCY_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+ ControllerPeriodicTasksConf.RETENTION_MANAGER_FREQUENCY_PERIOD,
period))
.map(period -> (int) convertPeriodToSeconds(period)).orElseGet(
() ->
getProperty(ControllerPeriodicTasksConf.DEPRECATED_RETENTION_MANAGER_FREQUENCY_IN_SECONDS,
ControllerPeriodicTasksConf.DEFAULT_RETENTION_MANAGER_FREQUENCY_IN_SECONDS));
@@ -625,6 +630,8 @@ public class ControllerConf extends PinotConfiguration {
public int getOfflineSegmentIntervalCheckerFrequencyInSeconds() {
return Optional.ofNullable(
getProperty(ControllerPeriodicTasksConf.OFFLINE_SEGMENT_INTERVAL_CHECKER_FREQUENCY_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+
ControllerPeriodicTasksConf.OFFLINE_SEGMENT_INTERVAL_CHECKER_FREQUENCY_PERIOD,
period))
.map(period -> (int) convertPeriodToSeconds(period)).orElseGet(() ->
getProperty(
ControllerPeriodicTasksConf.DEPRECATED_OFFLINE_SEGMENT_INTERVAL_CHECKER_FREQUENCY_IN_SECONDS,
ControllerPeriodicTasksConf.DEFAULT_OFFLINE_SEGMENT_INTERVAL_CHECKER_FREQUENCY_IN_SECONDS));
@@ -647,6 +654,8 @@ public class ControllerConf extends PinotConfiguration {
*/
public int getRealtimeSegmentValidationFrequencyInSeconds() {
return
Optional.ofNullable(getProperty(ControllerPeriodicTasksConf.REALTIME_SEGMENT_VALIDATION_FREQUENCY_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+
ControllerPeriodicTasksConf.REALTIME_SEGMENT_VALIDATION_FREQUENCY_PERIOD,
period))
.map(period -> (int) convertPeriodToSeconds(period)).orElseGet(
() ->
getProperty(ControllerPeriodicTasksConf.DEPRECATED_REALTIME_SEGMENT_VALIDATION_FREQUENCY_IN_SECONDS,
ControllerPeriodicTasksConf.DEFAULT_REALTIME_SEGMENT_VALIDATION_FREQUENCY_IN_SECONDS));
@@ -669,6 +678,8 @@ public class ControllerConf extends PinotConfiguration {
*/
public int getBrokerResourceValidationFrequencyInSeconds() {
return
Optional.ofNullable(getProperty(ControllerPeriodicTasksConf.BROKER_RESOURCE_VALIDATION_FREQUENCY_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+
ControllerPeriodicTasksConf.BROKER_RESOURCE_VALIDATION_FREQUENCY_PERIOD,
period))
.map(period -> (int) convertPeriodToSeconds(period)).orElseGet(
() ->
getProperty(ControllerPeriodicTasksConf.DEPRECATED_BROKER_RESOURCE_VALIDATION_FREQUENCY_IN_SECONDS,
ControllerPeriodicTasksConf.DEFAULT_BROKER_RESOURCE_VALIDATION_FREQUENCY_IN_SECONDS));
@@ -686,6 +697,7 @@ public class ControllerConf extends PinotConfiguration {
public int getStatusCheckerFrequencyInSeconds() {
return
Optional.ofNullable(getProperty(ControllerPeriodicTasksConf.STATUS_CHECKER_FREQUENCY_PERIOD))
+ .filter(period ->
isValidPeriodWithLogging(ControllerPeriodicTasksConf.STATUS_CHECKER_FREQUENCY_PERIOD,
period))
.map(period -> (int) convertPeriodToSeconds(period)).orElseGet(
() ->
getProperty(ControllerPeriodicTasksConf.DEPRECATED_STATUS_CHECKER_FREQUENCY_IN_SECONDS,
ControllerPeriodicTasksConf.DEFAULT_STATUS_CHECKER_FREQUENCY_IN_SECONDS));
@@ -698,6 +710,8 @@ public class ControllerConf extends PinotConfiguration {
public int getRebalanceCheckerFrequencyInSeconds() {
return
Optional.ofNullable(getProperty(ControllerPeriodicTasksConf.REBALANCE_CHECKER_FREQUENCY_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+ ControllerPeriodicTasksConf.REBALANCE_CHECKER_FREQUENCY_PERIOD,
period))
.map(period -> (int) convertPeriodToSeconds(period))
.orElse(ControllerPeriodicTasksConf.DEFAULT_REBALANCE_CHECKER_FREQUENCY_IN_SECONDS);
}
@@ -720,6 +734,8 @@ public class ControllerConf extends PinotConfiguration {
public int getTaskMetricsEmitterFrequencyInSeconds() {
return
Optional.ofNullable(getProperty(ControllerPeriodicTasksConf.TASK_METRICS_EMITTER_FREQUENCY_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+ ControllerPeriodicTasksConf.TASK_METRICS_EMITTER_FREQUENCY_PERIOD,
period))
.map(period -> (int) convertPeriodToSeconds(period)).orElseGet(
() ->
getProperty(ControllerPeriodicTasksConf.DEPRECATED_TASK_METRICS_EMITTER_FREQUENCY_IN_SECONDS,
ControllerPeriodicTasksConf.DEFAULT_TASK_METRICS_EMITTER_FREQUENCY_IN_SECONDS));
@@ -732,6 +748,8 @@ public class ControllerConf extends PinotConfiguration {
public int getStatusCheckerWaitForPushTimeInSeconds() {
return
Optional.ofNullable(getProperty(ControllerPeriodicTasksConf.STATUS_CHECKER_WAIT_FOR_PUSH_TIME_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+
ControllerPeriodicTasksConf.STATUS_CHECKER_WAIT_FOR_PUSH_TIME_PERIOD, period))
.map(period -> (int) convertPeriodToSeconds(period)).orElseGet(
() ->
getProperty(ControllerPeriodicTasksConf.DEPRECATED_STATUS_CHECKER_WAIT_FOR_PUSH_TIME_IN_SECONDS,
ControllerPeriodicTasksConf.DEFAULT_STATUS_CONTROLLER_WAIT_FOR_PUSH_TIME_IN_SECONDS));
@@ -749,6 +767,8 @@ public class ControllerConf extends PinotConfiguration {
*/
public int getSegmentRelocatorFrequencyInSeconds() {
return
Optional.ofNullable(getProperty(ControllerPeriodicTasksConf.SEGMENT_RELOCATOR_FREQUENCY_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+ ControllerPeriodicTasksConf.SEGMENT_RELOCATOR_FREQUENCY_PERIOD,
period))
.map(period -> (int) convertPeriodToSeconds(period)).orElseGet(() -> {
Integer segmentRelocatorFreqSeconds =
getProperty(ControllerPeriodicTasksConf.DEPRECATED_SEGMENT_RELOCATOR_FREQUENCY_IN_SECONDS,
Integer.class);
@@ -877,6 +897,8 @@ public class ControllerConf extends PinotConfiguration {
public int getTaskManagerFrequencyInSeconds() {
return
Optional.ofNullable(getProperty(ControllerPeriodicTasksConf.TASK_MANAGER_FREQUENCY_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+ ControllerPeriodicTasksConf.TASK_MANAGER_FREQUENCY_PERIOD, period))
.map(period -> (int) convertPeriodToSeconds(period)).orElseGet(
() ->
getProperty(ControllerPeriodicTasksConf.DEPRECATED_TASK_MANAGER_FREQUENCY_IN_SECONDS,
ControllerPeriodicTasksConf.DEFAULT_TASK_MANAGER_FREQUENCY_IN_SECONDS));
@@ -890,6 +912,8 @@ public class ControllerConf extends PinotConfiguration {
@Deprecated
public int getMinionInstancesCleanupTaskFrequencyInSeconds() {
return
Optional.ofNullable(getProperty(ControllerPeriodicTasksConf.MINION_INSTANCES_CLEANUP_TASK_FREQUENCY_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+
ControllerPeriodicTasksConf.MINION_INSTANCES_CLEANUP_TASK_FREQUENCY_PERIOD,
period))
.map(period -> (int) convertPeriodToSeconds(period)).orElseGet(
() ->
getProperty(ControllerPeriodicTasksConf.DEPRECATED_MINION_INSTANCES_CLEANUP_TASK_FREQUENCY_IN_SECONDS,
ControllerPeriodicTasksConf.DEFAULT_MINION_INSTANCES_CLEANUP_TASK_FREQUENCY_IN_SECONDS));
@@ -917,6 +941,8 @@ public class ControllerConf extends PinotConfiguration {
public int
getMinionInstancesCleanupTaskMinOfflineTimeBeforeDeletionInSeconds() {
return Optional.ofNullable(
getProperty(ControllerPeriodicTasksConf.MINION_INSTANCES_CLEANUP_TASK_MIN_OFFLINE_TIME_BEFORE_DELETION_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+
ControllerPeriodicTasksConf.MINION_INSTANCES_CLEANUP_TASK_MIN_OFFLINE_TIME_BEFORE_DELETION_PERIOD,
period))
.map(period -> (int) convertPeriodToSeconds(period)).orElseGet(() ->
getProperty(
ControllerPeriodicTasksConf.
DEPRECATED_MINION_INSTANCES_CLEANUP_TASK_MIN_OFFLINE_TIME_BEFORE_DELETION_SECONDS,
@@ -933,6 +959,8 @@ public class ControllerConf extends PinotConfiguration {
public int getStaleInstancesCleanupTaskFrequencyInSeconds() {
return
Optional.ofNullable(getProperty(ControllerPeriodicTasksConf.STALE_INSTANCES_CLEANUP_TASK_FREQUENCY_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+
ControllerPeriodicTasksConf.STALE_INSTANCES_CLEANUP_TASK_FREQUENCY_PERIOD,
period))
.map(period -> (int) convertPeriodToSeconds(period))
// Backward compatible for existing users who configured
MinionInstancesCleanupTask
.orElse(getMinionInstancesCleanupTaskFrequencyInSeconds());
@@ -955,6 +983,8 @@ public class ControllerConf extends PinotConfiguration {
public int getStaleInstancesCleanupTaskInstancesRetentionInSeconds() {
return Optional.ofNullable(
getProperty(ControllerPeriodicTasksConf.STALE_INSTANCES_CLEANUP_TASK_INSTANCES_RETENTION_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+
ControllerPeriodicTasksConf.STALE_INSTANCES_CLEANUP_TASK_INSTANCES_RETENTION_PERIOD,
period))
.map(period -> (int) convertPeriodToSeconds(period))
// Backward compatible for existing users who configured
MinionInstancesCleanupTask
.orElse(getMinionInstancesCleanupTaskMinOfflineTimeBeforeDeletionInSeconds());
@@ -1076,13 +1106,16 @@ public class ControllerConf extends PinotConfiguration {
return getProperty(ENABLE_HYBRID_TABLE_RETENTION_STRATEGY,
DEFAULT_ENABLE_HYBRID_TABLE_RETENTION_STRATEGY);
}
- public int getSegmentLevelValidationIntervalInSeconds() {
- return
Optional.ofNullable(getProperty(ControllerPeriodicTasksConf.SEGMENT_LEVEL_VALIDATION_INTERVAL_PERIOD))
- .map(period -> (int) convertPeriodToSeconds(period)).orElseGet(
- () ->
getProperty(ControllerPeriodicTasksConf.DEPRECATED_SEGMENT_LEVEL_VALIDATION_INTERVAL_IN_SECONDS,
-
ControllerPeriodicTasksConf.DEFAULT_SEGMENT_LEVEL_VALIDATION_INTERVAL_IN_SECONDS));
+ public int getSegmentLevelValidationIntervalInSeconds() {
+ return
Optional.ofNullable(getProperty(ControllerPeriodicTasksConf.SEGMENT_LEVEL_VALIDATION_INTERVAL_PERIOD))
+ .filter(period -> isValidPeriodWithLogging(
+
ControllerPeriodicTasksConf.SEGMENT_LEVEL_VALIDATION_INTERVAL_PERIOD, period))
+ .map(period -> (int) convertPeriodToSeconds(period)).orElseGet(
+ () ->
getProperty(ControllerPeriodicTasksConf.DEPRECATED_SEGMENT_LEVEL_VALIDATION_INTERVAL_IN_SECONDS,
+
ControllerPeriodicTasksConf.DEFAULT_SEGMENT_LEVEL_VALIDATION_INTERVAL_IN_SECONDS));
}
+
public boolean isAutoResetErrorSegmentsOnValidationEnabled() {
return
getProperty(ControllerPeriodicTasksConf.AUTO_RESET_ERROR_SEGMENTS_VALIDATION,
false);
}
@@ -1226,6 +1259,25 @@ public class ControllerConf extends PinotConfiguration {
return convertPeriodToUnit(period, TimeUnit.SECONDS);
}
+ private boolean isValidPeriodWithLogging(String propertyKey, String
periodStr) {
+ if (TimeUtils.isPeriodValid(periodStr)) {
+ return true;
+ } else {
+ addControllerInvalidConfigs(propertyKey,
+ String.format("Invalid time spec '%s' for config '%s'. Falling back
to default config.",
+ periodStr, propertyKey));
+ return false;
+ }
+ }
+
+ private void addControllerInvalidConfigs(String propertyKey, String
errorMessage) {
+ _invalidConfigs.put(propertyKey, errorMessage);
+ }
+
+ public Map<String, String> getInvalidConfigs() {
+ return _invalidConfigs;
+ }
+
private String getSupportedProtocol(String property) {
String value = getProperty(property, CommonConstants.HTTP_PROTOCOL);
Preconditions.checkArgument(SUPPORTED_PROTOCOLS.contains(value),
"Unsupported %s protocol '%s'", property, value);
diff --git
a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotControllerHealthCheck.java
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotControllerHealthCheck.java
index 61a18352ea..cf1de22181 100644
---
a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotControllerHealthCheck.java
+++
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotControllerHealthCheck.java
@@ -29,6 +29,8 @@ import io.swagger.annotations.SwaggerDefinition;
import java.time.Duration;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.GET;
@@ -119,6 +121,20 @@ public class PinotControllerHealthCheck {
return uptime.getSeconds();
}
+ @GET
+ @Path("invalidconfigs")
+ @Authorize(targetType = TargetType.CLUSTER, action =
Actions.Cluster.GET_HEALTH)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(value = "List invalid controller configs")
+ public Response getConfigWarnings() {
+ Map<String, String> warnings = _controllerConf.getInvalidConfigs();
+ if (warnings.isEmpty()) {
+ return Response.ok(Collections.emptyMap()).build();
+ }
+
+ return Response.ok(warnings).build();
+ }
+
@GET
@Path("start-time")
@Authorize(targetType = TargetType.CLUSTER, action =
Actions.Cluster.GET_HEALTH)
diff --git
a/pinot-controller/src/test/java/org/apache/pinot/controller/ControllerConfTest.java
b/pinot-controller/src/test/java/org/apache/pinot/controller/ControllerConfTest.java
index c65a1b7a9f..120da8e8db 100644
---
a/pinot-controller/src/test/java/org/apache/pinot/controller/ControllerConfTest.java
+++
b/pinot-controller/src/test/java/org/apache/pinot/controller/ControllerConfTest.java
@@ -88,9 +88,10 @@ public class ControllerConfTest {
* are thrown when invalid new configurations are read (there is no
fall-back to the corresponding
* valid deprecated configuration). For all valid new configurations, they
override the
* corresponding deprecated configuration.
+ * Added fallback logic to use valid deprecated config when new config is
invalid.
*/
@Test
- public void
invalidNewConfigShouldThrowExceptionOnReadWithoutFallbackToCorrespondingValidDeprecatedConfig()
{
+ public void
invalidNewConfigShouldNotThrowExceptionOnReadWithFallbackToCorrespondingValidDeprecatedConfig()
{
//setup
Map<String, Object> controllerConfig = new HashMap<>();
int durationInSeconds = getRandomDurationInSeconds();
@@ -99,9 +100,24 @@ public class ControllerConfTest {
String randomPeriodInMinutes = getRandomPeriodInMinutes();
NEW_CONFIGS.forEach(config -> controllerConfig.put(config,
randomPeriodInMinutes));
//put some invalid new configs
- controllerConfig.put(RETENTION_MANAGER_FREQUENCY_PERIOD,
getRandomString());
+ String randomInvalidString = getRandomString();
+ controllerConfig.put(RETENTION_MANAGER_FREQUENCY_PERIOD,
randomInvalidString);
ControllerConf conf = new ControllerConf(controllerConfig);
- Assert.assertThrows(IllegalArgumentException.class,
conf::getRetentionControllerFrequencyInSeconds);
+ Assert.assertEquals(
+ conf.getRetentionControllerFrequencyInSeconds(),
+ durationInSeconds, // expected fallback value
+ "Should fallback to deprecated config value"
+ );
+ //test to assert that invalid config is captured in the invalid config map
value
+ Map<String, String> invalidConfigs = conf.getInvalidConfigs();
+
Assert.assertTrue(invalidConfigs.containsKey(RETENTION_MANAGER_FREQUENCY_PERIOD));
+ Assert.assertEquals(
+ conf.getInvalidConfigs().get(RETENTION_MANAGER_FREQUENCY_PERIOD),
+ String.format(
+ "Invalid time spec '%s' for config '%s'. Falling back to default
config.",
+ randomInvalidString, RETENTION_MANAGER_FREQUENCY_PERIOD
+ )
+ );
}
/**
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]