This is an automated email from the ASF dual-hosted git repository. somandal 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 0dca00766ec Update the UtilizationChecker and ResourceUtilizationManager to return an enum instead of boolean (#16255) 0dca00766ec is described below commit 0dca00766ecc8a5abc8b2fe5c8e036503b19eacb Author: Sonam Mandal <sonam.man...@startree.ai> AuthorDate: Wed Jul 2 11:16:57 2025 -0700 Update the UtilizationChecker and ResourceUtilizationManager to return an enum instead of boolean (#16255) --- .../helix/core/minion/PinotTaskManager.java | 8 ++-- .../validation/DiskUtilizationChecker.java | 19 ++++++-- .../RealtimeSegmentValidationManager.java | 16 +++++-- .../validation/ResourceUtilizationManager.java | 28 ++++++++--- .../controller/validation/UtilizationChecker.java | 12 ++++- .../validation/DiskUtilizationCheckerTest.java | 56 ++++++++++++++++------ .../RealtimeSegmentValidationManagerTest.java | 27 +++++++---- .../validation/ResourceUtilizationManagerTest.java | 54 +++++++++++++++------ 8 files changed, 163 insertions(+), 57 deletions(-) diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/minion/PinotTaskManager.java b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/minion/PinotTaskManager.java index 96f9154241f..8303eb67f4f 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/minion/PinotTaskManager.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/minion/PinotTaskManager.java @@ -223,8 +223,8 @@ public class PinotTaskManager extends ControllerPeriodicTask<Void> { TableConfig tableConfig = _pinotHelixResourceManager.getTableConfig(tableNameWithType); LOGGER.info("Trying to create tasks of type: {}, table: {}", taskType, tableNameWithType); try { - if (!_resourceUtilizationManager.isResourceUtilizationWithinLimits(tableNameWithType, - UtilizationChecker.CheckPurpose.TASK_GENERATION)) { + if (_resourceUtilizationManager.isResourceUtilizationWithinLimits(tableNameWithType, + UtilizationChecker.CheckPurpose.TASK_GENERATION) == UtilizationChecker.CheckResult.FAIL) { LOGGER.warn("Resource utilization is above threshold, skipping task creation for table: {}", tableName); _controllerMetrics.setOrUpdateTableGauge(tableName, ControllerGauge.RESOURCE_UTILIZATION_LIMIT_EXCEEDED, 1L); continue; @@ -723,8 +723,8 @@ public class PinotTaskManager extends ControllerPeriodicTask<Void> { for (TableConfig tableConfig : enabledTableConfigs) { String tableName = tableConfig.getTableName(); try { - if (!_resourceUtilizationManager.isResourceUtilizationWithinLimits(tableName, - UtilizationChecker.CheckPurpose.TASK_GENERATION)) { + if (_resourceUtilizationManager.isResourceUtilizationWithinLimits(tableName, + UtilizationChecker.CheckPurpose.TASK_GENERATION) == UtilizationChecker.CheckResult.FAIL) { String message = String.format("Skipping tasks generation as resource utilization is not within limits for " + "table: %s. Disk utilization for one or more servers hosting this table has exceeded the threshold. " + "Tasks won't be generated until the issue is mitigated.", tableName); diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/validation/DiskUtilizationChecker.java b/pinot-controller/src/main/java/org/apache/pinot/controller/validation/DiskUtilizationChecker.java index fa2f1bfbea2..45616227b85 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/validation/DiskUtilizationChecker.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/validation/DiskUtilizationChecker.java @@ -63,14 +63,14 @@ public class DiskUtilizationChecker implements UtilizationChecker { * Check if disk utilization for the requested table is within the configured limits. */ @Override - public boolean isResourceUtilizationWithinLimits(String tableNameWithType, UtilizationChecker.CheckPurpose purpose) { + public CheckResult isResourceUtilizationWithinLimits(String tableNameWithType, CheckPurpose purpose) { if (StringUtils.isEmpty(tableNameWithType)) { throw new IllegalArgumentException("Table name found to be null or empty while computing disk utilization."); } TableConfig tableConfig = _helixResourceManager.getTableConfig(tableNameWithType); if (tableConfig == null) { LOGGER.warn("Table config for table: {} is null", tableNameWithType); - return true; // table does not exist + return CheckResult.PASS; // table does not exist } List<String> instances; if (TableNameBuilder.isOfflineTableResource(tableNameWithType)) { @@ -81,10 +81,12 @@ public class DiskUtilizationChecker implements UtilizationChecker { return isDiskUtilizationWithinLimits(instances); } - private boolean isDiskUtilizationWithinLimits(List<String> instances) { + private CheckResult isDiskUtilizationWithinLimits(List<String> instances) { + int numInstancesWithStaleOrNullResults = 0; for (String instance : instances) { DiskUsageInfo diskUsageInfo = ResourceUtilizationInfo.getDiskUsageInfo(instance); if (diskUsageInfo == null) { + numInstancesWithStaleOrNullResults++; LOGGER.warn("Disk utilization info for server: {} is null", instance); continue; } @@ -92,6 +94,7 @@ public class DiskUtilizationChecker implements UtilizationChecker { // ResourceUtilizationChecker tasks frequency. if (diskUsageInfo.getLastUpdatedTimeInEpochMs() < System.currentTimeMillis() - _resourceUtilizationCheckerFrequencyMs) { + numInstancesWithStaleOrNullResults++; LOGGER.warn("Disk utilization info for server: {} is stale", instance); continue; } @@ -99,10 +102,16 @@ public class DiskUtilizationChecker implements UtilizationChecker { LOGGER.warn("Disk utilization for server: {} is above threshold: {}%. UsedBytes: {}, TotalBytes: {}", instance, diskUsageInfo.getUsedSpaceBytes() * 100 / diskUsageInfo.getTotalSpaceBytes(), diskUsageInfo .getUsedSpaceBytes(), diskUsageInfo.getTotalSpaceBytes()); - return false; + return CheckResult.FAIL; } } - return true; + // If results for all servers is null or stale, return the status as STALE to indicate that the status cannot be + // determined. + // TODO: Have better handling for partial STALE results from servers. It is possible that a subset of servers are + // STALE, and these are the ones that may have a resource utilization breach, but we return TRUE here. + // Eventually when the status is updated, the correct value will be returned and the correct action can be + // taken based on that. Temporarily the action taken may be the wrong one. + return numInstancesWithStaleOrNullResults == instances.size() ? CheckResult.UNDETERMINED : CheckResult.PASS; } /** diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/validation/RealtimeSegmentValidationManager.java b/pinot-controller/src/main/java/org/apache/pinot/controller/validation/RealtimeSegmentValidationManager.java index 39cf6f1b75f..d5ac06062c3 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/validation/RealtimeSegmentValidationManager.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/validation/RealtimeSegmentValidationManager.java @@ -156,10 +156,10 @@ public class RealtimeSegmentValidationManager extends ControllerPeriodicTask<Rea return false; // if table is paused by admin, then skip subsequent checks } // Perform resource utilization checks. - boolean isResourceUtilizationWithinLimits = + UtilizationChecker.CheckResult isResourceUtilizationWithinLimits = _resourceUtilizationManager.isResourceUtilizationWithinLimits(tableNameWithType, UtilizationChecker.CheckPurpose.REALTIME_INGESTION); - if (!isResourceUtilizationWithinLimits) { + if (isResourceUtilizationWithinLimits == UtilizationChecker.CheckResult.FAIL) { LOGGER.warn("Resource utilization limit exceeded for table: {}", tableNameWithType); _controllerMetrics.setOrUpdateTableGauge(tableNameWithType, ControllerGauge.RESOURCE_UTILIZATION_LIMIT_EXCEEDED, 1L); @@ -170,14 +170,22 @@ public class RealtimeSegmentValidationManager extends ControllerPeriodicTask<Rea PauseState.ReasonCode.RESOURCE_UTILIZATION_LIMIT_EXCEEDED, "Resource utilization limit exceeded."); } return false; // if resource utilization check failed, then skip subsequent checks + } else if ((isResourceUtilizationWithinLimits == UtilizationChecker.CheckResult.PASS) && isTablePaused + && pauseStatus.getReasonCode().equals(PauseState.ReasonCode.RESOURCE_UTILIZATION_LIMIT_EXCEEDED)) { // within limits and table previously paused by resource utilization --> unpause - } else if (isTablePaused && pauseStatus.getReasonCode() - .equals(PauseState.ReasonCode.RESOURCE_UTILIZATION_LIMIT_EXCEEDED)) { + LOGGER.info("Resource utilization limit is back within limits for table: {}", tableNameWithType); // unset the pause state and allow consuming segment recreation. _llcRealtimeSegmentManager.updatePauseStateInIdealState(tableNameWithType, false, PauseState.ReasonCode.RESOURCE_UTILIZATION_LIMIT_EXCEEDED, "Resource utilization within limits"); pauseStatus = _llcRealtimeSegmentManager.getPauseStatusDetails(tableNameWithType); isTablePaused = pauseStatus.getPauseFlag(); + } else if ((isResourceUtilizationWithinLimits == UtilizationChecker.CheckResult.UNDETERMINED) && isTablePaused + && pauseStatus.getReasonCode().equals(PauseState.ReasonCode.RESOURCE_UTILIZATION_LIMIT_EXCEEDED)) { + // The table was previously paused due to exceeding resource utilization, but the current status cannot be + // determined. To be safe, leave it as paused and once the status is available take the correct action + LOGGER.warn("Resource utilization limit could not be determined for for table: {}, and it is paused, leave it as " + + "paused", tableNameWithType); + return false; } _controllerMetrics.setOrUpdateTableGauge(tableNameWithType, ControllerGauge.RESOURCE_UTILIZATION_LIMIT_EXCEEDED, 0L); diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/validation/ResourceUtilizationManager.java b/pinot-controller/src/main/java/org/apache/pinot/controller/validation/ResourceUtilizationManager.java index 396d6ba68c4..cda90ed71eb 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/validation/ResourceUtilizationManager.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/validation/ResourceUtilizationManager.java @@ -38,22 +38,38 @@ public class ResourceUtilizationManager { _utilizationCheckers = utilizationCheckers; } - public boolean isResourceUtilizationWithinLimits(String tableNameWithType, UtilizationChecker.CheckPurpose purpose) { + /** + * Returns the status of the resource utilization check across all UtilizationCheckers + * @param tableNameWithType table name with type + * @param purpose the purpose of the utilization check + * @return CheckResult, FAIL if even one resource utilization checker has returned FALSE, UNDETERMINED if the result + * cannot be determined for even one UtilizationChecker and all the others are also UNDETERMINED or PASS, + * and PASS if resource utilization is within limits for all UtilizationCheckers + */ + public UtilizationChecker.CheckResult isResourceUtilizationWithinLimits(String tableNameWithType, + UtilizationChecker.CheckPurpose purpose) { if (!_isResourceUtilizationCheckEnabled) { - return true; + return UtilizationChecker.CheckResult.PASS; } if (StringUtils.isEmpty(tableNameWithType)) { throw new IllegalArgumentException("Table name found to be null or empty while checking resource utilization."); } LOGGER.info("Checking resource utilization for table: {}", tableNameWithType); - boolean overallIsResourceUtilizationWithinLimits = true; + UtilizationChecker.CheckResult overallIsResourceUtilizationWithinLimits = UtilizationChecker.CheckResult.PASS; for (UtilizationChecker utilizationChecker : _utilizationCheckers) { - boolean isResourceUtilizationWithinLimits = + UtilizationChecker.CheckResult isResourceUtilizationWithinLimits = utilizationChecker.isResourceUtilizationWithinLimits(tableNameWithType, purpose); LOGGER.info("For utilization checker: {}, isResourceUtilizationWithinLimits: {}, purpose: {}", utilizationChecker.getName(), isResourceUtilizationWithinLimits, purpose); - if (!isResourceUtilizationWithinLimits) { - overallIsResourceUtilizationWithinLimits = false; + if (isResourceUtilizationWithinLimits == UtilizationChecker.CheckResult.FAIL) { + // If any UtilizationChecker returns FAIL, we should mark the overall as FAIL. FAIL should always have + // priority over other results + overallIsResourceUtilizationWithinLimits = UtilizationChecker.CheckResult.FAIL; + } else if ((overallIsResourceUtilizationWithinLimits == UtilizationChecker.CheckResult.PASS) + && (isResourceUtilizationWithinLimits == UtilizationChecker.CheckResult.UNDETERMINED)) { + // If we haven't already updated the overall to a value other than PASS, and we get an UNDETERMINED result, + // update the overall to UNDETERMINED. Should not update to UNDETERMINED if we have set the overall to FAIL + overallIsResourceUtilizationWithinLimits = UtilizationChecker.CheckResult.UNDETERMINED; } } return overallIsResourceUtilizationWithinLimits; diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/validation/UtilizationChecker.java b/pinot-controller/src/main/java/org/apache/pinot/controller/validation/UtilizationChecker.java index 2a4cdc9ce19..7b122bb98f1 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/validation/UtilizationChecker.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/validation/UtilizationChecker.java @@ -32,11 +32,12 @@ public interface UtilizationChecker { String getName(); /** - * Returns true if the resource's utilization is within limits + * Returns whether the resource's utilization is within limits * @param tableNameWithType table name with type * @param purpose purpose of this check + * @return CheckResult, UNDETERMINED if result cannot be determined, PASS if within limits, FAIL if not within limits */ - boolean isResourceUtilizationWithinLimits(String tableNameWithType, CheckPurpose purpose); + CheckResult isResourceUtilizationWithinLimits(String tableNameWithType, CheckPurpose purpose); /** * Computes the resource's utilization @@ -55,4 +56,11 @@ public interface UtilizationChecker { // TASK_GENERATION if the check is performed from the task generation framework to pause creation of new tasks REALTIME_INGESTION, TASK_GENERATION } + + enum CheckResult { + // PASS if the resource's utilization is within limits + // FAIL if the resource's utilization is not within limits + // UNDETERMINED if the result cannot be determined due to not having sufficient information + PASS, FAIL, UNDETERMINED + } } diff --git a/pinot-controller/src/test/java/org/apache/pinot/controller/validation/DiskUtilizationCheckerTest.java b/pinot-controller/src/test/java/org/apache/pinot/controller/validation/DiskUtilizationCheckerTest.java index 3e29c0c57f7..4643fc7aa04 100644 --- a/pinot-controller/src/test/java/org/apache/pinot/controller/validation/DiskUtilizationCheckerTest.java +++ b/pinot-controller/src/test/java/org/apache/pinot/controller/validation/DiskUtilizationCheckerTest.java @@ -80,27 +80,55 @@ public class DiskUtilizationCheckerTest { String tableName = "test_OFFLINE"; when(_helixResourceManager.getOfflineTableConfig(tableName)).thenReturn(null); - boolean result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, + UtilizationChecker.CheckResult result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, UtilizationChecker.CheckPurpose.REALTIME_INGESTION); - Assert.assertTrue(result); + Assert.assertEquals(result, UtilizationChecker.CheckResult.PASS); result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, UtilizationChecker.CheckPurpose.TASK_GENERATION); - Assert.assertTrue(result); + Assert.assertEquals(result, UtilizationChecker.CheckResult.PASS); } @Test public void testIsDiskUtilizationWithinLimitsNonExistentRealtimeTable() { String tableName = "test_REALTIME"; - when(_helixResourceManager.getRealtimeTableConfig(tableName)).thenReturn(null); + when(_helixResourceManager.getTableConfig(tableName)).thenReturn(null); - boolean result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, + UtilizationChecker.CheckResult result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, UtilizationChecker.CheckPurpose.REALTIME_INGESTION); - Assert.assertTrue(result); + Assert.assertEquals(result, UtilizationChecker.CheckResult.PASS); result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, UtilizationChecker.CheckPurpose.TASK_GENERATION); - Assert.assertTrue(result); + Assert.assertEquals(result, UtilizationChecker.CheckResult.PASS); + } + + @Test + public void testIsDiskUtilizationStale() { + String tableName = "test_OFFLINE"; + + TableConfig mockTableConfig = mock(TableConfig.class); + when(_helixResourceManager.getTableConfig(tableName)).thenReturn(mockTableConfig); + + List<String> mockInstances = Arrays.asList("server1", "server2"); + when(_helixResourceManager.getServerInstancesForTable(tableName, TableType.OFFLINE)).thenReturn(mockInstances); + + // Mock disk usage + Map<String, DiskUsageInfo> diskUsageInfoMap = new HashMap<>(); + DiskUsageInfo diskUsageInfo1 = new DiskUsageInfo("server1"); + diskUsageInfoMap.put("server1", diskUsageInfo1); + + DiskUsageInfo diskUsageInfo2 = new DiskUsageInfo("server2"); + diskUsageInfoMap.put("server2", diskUsageInfo2); + ResourceUtilizationInfo.setDiskUsageInfo(diskUsageInfoMap); + + UtilizationChecker.CheckResult result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, + UtilizationChecker.CheckPurpose.REALTIME_INGESTION); + Assert.assertEquals(result, UtilizationChecker.CheckResult.UNDETERMINED); + + result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, + UtilizationChecker.CheckPurpose.TASK_GENERATION); + Assert.assertEquals(result, UtilizationChecker.CheckResult.UNDETERMINED); } @Test @@ -108,7 +136,7 @@ public class DiskUtilizationCheckerTest { String tableName = "test_OFFLINE"; TableConfig mockTableConfig = mock(TableConfig.class); - when(_helixResourceManager.getOfflineTableConfig(tableName)).thenReturn(mockTableConfig); + when(_helixResourceManager.getTableConfig(tableName)).thenReturn(mockTableConfig); List<String> mockInstances = Arrays.asList("server1", "server2"); when(_helixResourceManager.getServerInstancesForTable(tableName, TableType.OFFLINE)).thenReturn(mockInstances); @@ -124,13 +152,13 @@ public class DiskUtilizationCheckerTest { diskUsageInfoMap.put("server2", diskUsageInfo2); ResourceUtilizationInfo.setDiskUsageInfo(diskUsageInfoMap); - boolean result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, + UtilizationChecker.CheckResult result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, UtilizationChecker.CheckPurpose.REALTIME_INGESTION); - Assert.assertTrue(result); + Assert.assertEquals(result, UtilizationChecker.CheckResult.PASS); result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, UtilizationChecker.CheckPurpose.TASK_GENERATION); - Assert.assertTrue(result); + Assert.assertEquals(result, UtilizationChecker.CheckResult.PASS); } @Test @@ -154,13 +182,13 @@ public class DiskUtilizationCheckerTest { diskUsageInfoMap.put("server2", diskUsageInfo2); ResourceUtilizationInfo.setDiskUsageInfo(diskUsageInfoMap); - boolean result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, + UtilizationChecker.CheckResult result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, UtilizationChecker.CheckPurpose.REALTIME_INGESTION); - Assert.assertFalse(result); + Assert.assertEquals(result, UtilizationChecker.CheckResult.FAIL); result = _diskUtilizationChecker.isResourceUtilizationWithinLimits(tableName, UtilizationChecker.CheckPurpose.TASK_GENERATION); - Assert.assertFalse(result); + Assert.assertEquals(result, UtilizationChecker.CheckResult.FAIL); } @Test diff --git a/pinot-controller/src/test/java/org/apache/pinot/controller/validation/RealtimeSegmentValidationManagerTest.java b/pinot-controller/src/test/java/org/apache/pinot/controller/validation/RealtimeSegmentValidationManagerTest.java index 9c435a48e88..4c74c0bc1f3 100644 --- a/pinot-controller/src/test/java/org/apache/pinot/controller/validation/RealtimeSegmentValidationManagerTest.java +++ b/pinot-controller/src/test/java/org/apache/pinot/controller/validation/RealtimeSegmentValidationManagerTest.java @@ -74,29 +74,40 @@ public class RealtimeSegmentValidationManagerTest { public Object[][] testCases() { return new Object[][]{ // Table is paused due to admin intervention, should return false - {true, PauseState.ReasonCode.ADMINISTRATIVE, false, false, false}, + {true, PauseState.ReasonCode.ADMINISTRATIVE, UtilizationChecker.CheckResult.PASS, false, false}, // Resource utilization exceeded and pause state is updated, should return false - {false, PauseState.ReasonCode.RESOURCE_UTILIZATION_LIMIT_EXCEEDED, true, false, false}, + {false, PauseState.ReasonCode.RESOURCE_UTILIZATION_LIMIT_EXCEEDED, UtilizationChecker.CheckResult.FAIL, false, + false}, // Resource utilization is within limits but was previously paused due to resource utilization, // should return true - {true, PauseState.ReasonCode.RESOURCE_UTILIZATION_LIMIT_EXCEEDED, false, false, true}, + {true, PauseState.ReasonCode.RESOURCE_UTILIZATION_LIMIT_EXCEEDED, UtilizationChecker.CheckResult.PASS, false, + true}, + + // Resource utilization is STALE but was previously paused due to resource utilization, should return false + {true, PauseState.ReasonCode.RESOURCE_UTILIZATION_LIMIT_EXCEEDED, UtilizationChecker.CheckResult.UNDETERMINED, + false, false}, + + // Resource utilization is STALE but was not previously paused due to resource utilization, should return true + {false, PauseState.ReasonCode.RESOURCE_UTILIZATION_LIMIT_EXCEEDED, UtilizationChecker.CheckResult.UNDETERMINED, + false, true}, // Resource utilization is within limits but was previously paused due to storage quota exceeded, // should return false - {true, PauseState.ReasonCode.STORAGE_QUOTA_EXCEEDED, false, true, false}, + {true, PauseState.ReasonCode.STORAGE_QUOTA_EXCEEDED, UtilizationChecker.CheckResult.PASS, true, false}, // Storage quota exceeded, should return false - {false, PauseState.ReasonCode.STORAGE_QUOTA_EXCEEDED, false, true, false}, + {false, PauseState.ReasonCode.STORAGE_QUOTA_EXCEEDED, UtilizationChecker.CheckResult.PASS, true, false}, // Storage quota within limits but was previously paused due to storage quota exceeded, should return true - {true, PauseState.ReasonCode.STORAGE_QUOTA_EXCEEDED, false, false, true}}; + {true, PauseState.ReasonCode.STORAGE_QUOTA_EXCEEDED, UtilizationChecker.CheckResult.PASS, false, true}}; } @Test(dataProvider = "testCases") public void testShouldEnsureConsuming(boolean isTablePaused, PauseState.ReasonCode reasonCode, - boolean isResourceUtilizationExceeded, boolean isQuotaExceeded, boolean expectedResult) { + UtilizationChecker.CheckResult isResourceUtilizationWithinLimits, boolean isQuotaExceeded, + boolean expectedResult) { String tableName = "testTable_REALTIME"; PauseStatusDetails pauseStatus = mock(PauseStatusDetails.class); TableConfig tableConfig = mock(TableConfig.class); @@ -105,7 +116,7 @@ public class RealtimeSegmentValidationManagerTest { when(pauseStatus.getReasonCode()).thenReturn(reasonCode); when(_llcRealtimeSegmentManager.getPauseStatusDetails(tableName)).thenReturn(pauseStatus); when(_resourceUtilizationManager.isResourceUtilizationWithinLimits(tableName, - UtilizationChecker.CheckPurpose.REALTIME_INGESTION)).thenReturn(!isResourceUtilizationExceeded); + UtilizationChecker.CheckPurpose.REALTIME_INGESTION)).thenReturn(isResourceUtilizationWithinLimits); when(_pinotHelixResourceManager.getTableConfig(tableName)).thenReturn(tableConfig); when(_storageQuotaChecker.isTableStorageQuotaExceeded(tableConfig)).thenReturn(isQuotaExceeded); diff --git a/pinot-controller/src/test/java/org/apache/pinot/controller/validation/ResourceUtilizationManagerTest.java b/pinot-controller/src/test/java/org/apache/pinot/controller/validation/ResourceUtilizationManagerTest.java index 9487105d530..a371d5dff40 100644 --- a/pinot-controller/src/test/java/org/apache/pinot/controller/validation/ResourceUtilizationManagerTest.java +++ b/pinot-controller/src/test/java/org/apache/pinot/controller/validation/ResourceUtilizationManagerTest.java @@ -46,13 +46,15 @@ public class ResourceUtilizationManagerTest { Mockito.when(_controllerConf.isResourceUtilizationCheckEnabled()).thenReturn(false); _resourceUtilizationManager = new ResourceUtilizationManager(_controllerConf, _utilizationCheckers); - boolean result = _resourceUtilizationManager.isResourceUtilizationWithinLimits(_testTable, + UtilizationChecker.CheckResult result = _resourceUtilizationManager.isResourceUtilizationWithinLimits(_testTable, UtilizationChecker.CheckPurpose.REALTIME_INGESTION); - Assert.assertTrue(result, "Resource utilization should be within limits when the check is disabled"); + Assert.assertEquals(result, UtilizationChecker.CheckResult.PASS, + "Resource utilization should be within limits when the check is disabled"); result = _resourceUtilizationManager.isResourceUtilizationWithinLimits(_testTable, UtilizationChecker.CheckPurpose.TASK_GENERATION); - Assert.assertTrue(result, "Resource utilization should be within limits when the check is disabled"); + Assert.assertEquals(result, UtilizationChecker.CheckResult.PASS, + "Resource utilization should be within limits when the check is disabled"); } @Test(expectedExceptions = IllegalArgumentException.class) @@ -95,35 +97,59 @@ public class ResourceUtilizationManagerTest { public void testIsResourceUtilizationWithinLimitsWhenCheckIsEnabled() { Mockito.when(_controllerConf.isResourceUtilizationCheckEnabled()).thenReturn(true); Mockito.when(_diskUtilizationChecker.isResourceUtilizationWithinLimits(_testTable, - UtilizationChecker.CheckPurpose.REALTIME_INGESTION)).thenReturn(true); + UtilizationChecker.CheckPurpose.REALTIME_INGESTION)).thenReturn(UtilizationChecker.CheckResult.PASS); _resourceUtilizationManager = new ResourceUtilizationManager(_controllerConf, _utilizationCheckers); - boolean result = _resourceUtilizationManager.isResourceUtilizationWithinLimits(_testTable, + UtilizationChecker.CheckResult result = _resourceUtilizationManager.isResourceUtilizationWithinLimits(_testTable, UtilizationChecker.CheckPurpose.REALTIME_INGESTION); - Assert.assertTrue(result, "Resource utilization should be within limits when disk check and primary key count " - + "check returns true"); + Assert.assertEquals(result, UtilizationChecker.CheckResult.PASS, + "Resource utilization should be within limits when disk check and primary key count check returns true"); Mockito.when(_diskUtilizationChecker.isResourceUtilizationWithinLimits(_testTable, - UtilizationChecker.CheckPurpose.TASK_GENERATION)).thenReturn(true); + UtilizationChecker.CheckPurpose.TASK_GENERATION)).thenReturn(UtilizationChecker.CheckResult.PASS); result = _resourceUtilizationManager.isResourceUtilizationWithinLimits(_testTable, UtilizationChecker.CheckPurpose.TASK_GENERATION); - Assert.assertTrue(result, "Resource utilization should be within limits when disk check and primary key count " - + "check returns true"); + Assert.assertEquals(result, UtilizationChecker.CheckResult.PASS, + "Resource utilization should be within limits when disk check and primary key count check returns true"); } @Test public void testIsResourceUtilizationWithinLimitsWhenCheckFails() { Mockito.when(_controllerConf.isResourceUtilizationCheckEnabled()).thenReturn(true); Mockito.when(_diskUtilizationChecker.isResourceUtilizationWithinLimits(_testTable, - UtilizationChecker.CheckPurpose.REALTIME_INGESTION)).thenReturn(false); + UtilizationChecker.CheckPurpose.REALTIME_INGESTION)).thenReturn(UtilizationChecker.CheckResult.FAIL); + Mockito.when(_diskUtilizationChecker.isResourceUtilizationWithinLimits(_testTable, + UtilizationChecker.CheckPurpose.TASK_GENERATION)).thenReturn(UtilizationChecker.CheckResult.FAIL); + _resourceUtilizationManager = new ResourceUtilizationManager(_controllerConf, _utilizationCheckers); + + UtilizationChecker.CheckResult result = _resourceUtilizationManager.isResourceUtilizationWithinLimits(_testTable, + UtilizationChecker.CheckPurpose.REALTIME_INGESTION); + Assert.assertEquals(result, UtilizationChecker.CheckResult.FAIL, + "Resource utilization should not be within limits when disk check returns false"); + + result = _resourceUtilizationManager.isResourceUtilizationWithinLimits(_testTable, + UtilizationChecker.CheckPurpose.TASK_GENERATION); + Assert.assertEquals(result, UtilizationChecker.CheckResult.FAIL, + "Resource utilization should not be within limits when disk check returns false"); + } + + @Test + public void testIsResourceUtilizationWithinLimitsWhenCheckStale() { + Mockito.when(_controllerConf.isResourceUtilizationCheckEnabled()).thenReturn(true); + Mockito.when(_diskUtilizationChecker.isResourceUtilizationWithinLimits(_testTable, + UtilizationChecker.CheckPurpose.REALTIME_INGESTION)).thenReturn(UtilizationChecker.CheckResult.UNDETERMINED); + Mockito.when(_diskUtilizationChecker.isResourceUtilizationWithinLimits(_testTable, + UtilizationChecker.CheckPurpose.TASK_GENERATION)).thenReturn(UtilizationChecker.CheckResult.UNDETERMINED); _resourceUtilizationManager = new ResourceUtilizationManager(_controllerConf, _utilizationCheckers); - boolean result = _resourceUtilizationManager.isResourceUtilizationWithinLimits(_testTable, + UtilizationChecker.CheckResult result = _resourceUtilizationManager.isResourceUtilizationWithinLimits(_testTable, UtilizationChecker.CheckPurpose.REALTIME_INGESTION); - Assert.assertFalse(result, "Resource utilization should not be within limits when disk check returns false"); + Assert.assertEquals(result, UtilizationChecker.CheckResult.UNDETERMINED, + "Resource utilization should return STALE when the diskUtilization returns STALE"); result = _resourceUtilizationManager.isResourceUtilizationWithinLimits(_testTable, UtilizationChecker.CheckPurpose.TASK_GENERATION); - Assert.assertFalse(result, "Resource utilization should not be within limits when disk check returns false"); + Assert.assertEquals(result, UtilizationChecker.CheckResult.UNDETERMINED, + "Resource utilization should return STALE when the diskUtilization returns STALE"); } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org