This is an automated email from the ASF dual-hosted git repository.
devesh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 374b3e7c05 HDDS-12708. Fix Unhealthy Containers API for pagination
(#8796)
374b3e7c05 is described below
commit 374b3e7c05b11ef577d6f344a0d33705a4f026d3
Author: Arafat2198 <[email protected]>
AuthorDate: Fri Jul 25 13:01:17 2025 +0530
HDDS-12708. Fix Unhealthy Containers API for pagination (#8796)
---
.../apache/hadoop/ozone/recon/TestReconTasks.java | 17 ++++---
.../recon/schema/ContainerSchemaDefinition.java | 8 +--
.../apache/hadoop/ozone/recon/ReconConstants.java | 2 +
.../ozone/recon/api/ClusterStateEndpoint.java | 3 +-
.../hadoop/ozone/recon/api/ContainerEndpoint.java | 50 ++++++++++++-------
.../api/types/UnhealthyContainersResponse.java | 33 ++++++++++++
.../persistence/ContainerHealthSchemaManager.java | 58 ++++++++++++++++++----
.../ozone/recon/api/TestContainerEndpoint.java | 34 +++++++++----
.../ozone/recon/fsck/TestContainerHealthTask.java | 3 +-
9 files changed, 156 insertions(+), 52 deletions(-)
diff --git
a/hadoop-ozone/integration-test-recon/src/test/java/org/apache/hadoop/ozone/recon/TestReconTasks.java
b/hadoop-ozone/integration-test-recon/src/test/java/org/apache/hadoop/ozone/recon/TestReconTasks.java
index c4a7dbb0fb..ed0ddde04c 100644
---
a/hadoop-ozone/integration-test-recon/src/test/java/org/apache/hadoop/ozone/recon/TestReconTasks.java
+++
b/hadoop-ozone/integration-test-recon/src/test/java/org/apache/hadoop/ozone/recon/TestReconTasks.java
@@ -28,6 +28,7 @@
import java.time.Duration;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
@@ -169,8 +170,8 @@ public void testMissingContainerDownNode() throws Exception
{
List<UnhealthyContainers> allMissingContainers =
reconContainerManager.getContainerSchemaManager()
.getUnhealthyContainers(
- ContainerSchemaDefinition.UnHealthyContainerStates.MISSING,
- 0, 1000);
+ ContainerSchemaDefinition.UnHealthyContainerStates.MISSING,
0L,
+ Optional.empty(), 1000);
return (allMissingContainers.size() == 1);
});
@@ -181,7 +182,7 @@ public void testMissingContainerDownNode() throws Exception
{
reconContainerManager.getContainerSchemaManager()
.getUnhealthyContainers(
ContainerSchemaDefinition.UnHealthyContainerStates.MISSING,
- 0, 1000);
+ 0L, Optional.empty(), 1000);
return (allMissingContainers.isEmpty());
});
IOUtils.closeQuietly(client);
@@ -247,7 +248,7 @@ public void testEmptyMissingContainerDownNode() throws
Exception {
.getUnhealthyContainers(
ContainerSchemaDefinition.UnHealthyContainerStates.
EMPTY_MISSING,
- 0, 1000);
+ 0L, Optional.empty(), 1000);
// Check if EMPTY_MISSING containers are not added to the DB and their
count is logged
Map<ContainerSchemaDefinition.UnHealthyContainerStates, Map<String,
Long>>
@@ -275,7 +276,7 @@ public void testEmptyMissingContainerDownNode() throws
Exception {
reconContainerManager.getContainerSchemaManager()
.getUnhealthyContainers(
ContainerSchemaDefinition.UnHealthyContainerStates.MISSING,
- 0, 1000);
+ 0L, Optional.empty(), 1000);
return (allMissingContainers.size() == 1);
});
@@ -285,7 +286,7 @@ public void testEmptyMissingContainerDownNode() throws
Exception {
.getUnhealthyContainers(
ContainerSchemaDefinition.UnHealthyContainerStates.
EMPTY_MISSING,
- 0, 1000);
+ 0L, Optional.empty(), 1000);
Map<ContainerSchemaDefinition.UnHealthyContainerStates, Map<String,
Long>>
@@ -315,7 +316,7 @@ public void testEmptyMissingContainerDownNode() throws
Exception {
.getUnhealthyContainers(
ContainerSchemaDefinition.UnHealthyContainerStates.
EMPTY_MISSING,
- 0, 1000);
+ 0L, Optional.empty(), 1000);
Map<ContainerSchemaDefinition.UnHealthyContainerStates, Map<String,
Long>>
unhealthyContainerStateStatsMap = reconScm.getContainerHealthTask()
@@ -335,7 +336,7 @@ public void testEmptyMissingContainerDownNode() throws
Exception {
reconContainerManager.getContainerSchemaManager()
.getUnhealthyContainers(
ContainerSchemaDefinition.UnHealthyContainerStates.MISSING,
- 0, 1000);
+ 0L, Optional.empty(), 1000);
return (allMissingContainers.isEmpty());
});
diff --git
a/hadoop-ozone/recon-codegen/src/main/java/org/apache/ozone/recon/schema/ContainerSchemaDefinition.java
b/hadoop-ozone/recon-codegen/src/main/java/org/apache/ozone/recon/schema/ContainerSchemaDefinition.java
index 5919028a56..05bf4f158d 100644
---
a/hadoop-ozone/recon-codegen/src/main/java/org/apache/ozone/recon/schema/ContainerSchemaDefinition.java
+++
b/hadoop-ozone/recon-codegen/src/main/java/org/apache/ozone/recon/schema/ContainerSchemaDefinition.java
@@ -37,11 +37,10 @@
*/
@Singleton
public class ContainerSchemaDefinition implements ReconSchemaDefinition {
+ private static final Logger LOG =
LoggerFactory.getLogger(ContainerSchemaDefinition.class);
public static final String UNHEALTHY_CONTAINERS_TABLE_NAME =
"UNHEALTHY_CONTAINERS";
- private static final Logger LOG =
- LoggerFactory.getLogger(ContainerSchemaDefinition.class);
private static final String CONTAINER_ID = "container_id";
private static final String CONTAINER_STATE = "container_state";
@@ -78,9 +77,12 @@ private void createUnhealthyContainersTable() {
.constraint(DSL.constraint("pk_container_id")
.primaryKey(CONTAINER_ID, CONTAINER_STATE))
.constraint(DSL.constraint(UNHEALTHY_CONTAINERS_TABLE_NAME + "ck1")
- .check(field(name("container_state"))
+ .check(field(name(CONTAINER_STATE))
.in(UnHealthyContainerStates.values())))
.execute();
+ dslContext.createIndex("idx_container_state")
+ .on(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME),
DSL.field(name(CONTAINER_STATE)))
+ .execute();
}
public DSLContext getDSLContext() {
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconConstants.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconConstants.java
index d1919f4f7b..396beb9e3f 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconConstants.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconConstants.java
@@ -46,6 +46,8 @@ public final class ReconConstants {
public static final String RECON_QUERY_BATCH_PARAM = "batchNum";
public static final String RECON_QUERY_PREVKEY = "prevKey";
public static final String RECON_QUERY_START_PREFIX = "startPrefix";
+ public static final String RECON_QUERY_MAX_CONTAINER_ID = "maxContainerId";
+ public static final String RECON_QUERY_MIN_CONTAINER_ID = "minContainerId";
public static final String RECON_OPEN_KEY_INCLUDE_NON_FSO = "includeNonFso";
public static final String RECON_OPEN_KEY_INCLUDE_FSO = "includeFso";
public static final String RECON_OM_INSIGHTS_DEFAULT_START_PREFIX = "/";
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ClusterStateEndpoint.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ClusterStateEndpoint.java
index e3bbf10fe1..8be9ef4746 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ClusterStateEndpoint.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ClusterStateEndpoint.java
@@ -27,6 +27,7 @@
import static org.apache.hadoop.ozone.om.codec.OMDBDefinition.VOLUME_TABLE;
import java.util.List;
+import java.util.Optional;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@@ -99,7 +100,7 @@ public Response getClusterState() {
List<UnhealthyContainers> missingContainers = containerHealthSchemaManager
.getUnhealthyContainers(
ContainerSchemaDefinition.UnHealthyContainerStates.MISSING,
- 0, MISSING_CONTAINER_COUNT_LIMIT);
+ 0L, Optional.empty(), MISSING_CONTAINER_COUNT_LIMIT);
containerStateCounts.setMissingContainerCount(
missingContainers.size() == MISSING_CONTAINER_COUNT_LIMIT ?
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
index 8ccfdbf827..89db23520d 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
@@ -17,13 +17,13 @@
package org.apache.hadoop.ozone.recon.api;
-import static
org.apache.hadoop.ozone.recon.ReconConstants.DEFAULT_BATCH_NUMBER;
import static org.apache.hadoop.ozone.recon.ReconConstants.DEFAULT_FETCH_COUNT;
import static
org.apache.hadoop.ozone.recon.ReconConstants.DEFAULT_FILTER_FOR_MISSING_CONTAINERS;
import static
org.apache.hadoop.ozone.recon.ReconConstants.PREV_CONTAINER_ID_DEFAULT_VALUE;
-import static
org.apache.hadoop.ozone.recon.ReconConstants.RECON_QUERY_BATCH_PARAM;
import static org.apache.hadoop.ozone.recon.ReconConstants.RECON_QUERY_FILTER;
import static org.apache.hadoop.ozone.recon.ReconConstants.RECON_QUERY_LIMIT;
+import static
org.apache.hadoop.ozone.recon.ReconConstants.RECON_QUERY_MAX_CONTAINER_ID;
+import static
org.apache.hadoop.ozone.recon.ReconConstants.RECON_QUERY_MIN_CONTAINER_ID;
import static org.apache.hadoop.ozone.recon.ReconConstants.RECON_QUERY_PREVKEY;
import java.io.IOException;
@@ -35,6 +35,7 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -339,7 +340,7 @@ public Response getMissingContainers(
) {
List<MissingContainerMetadata> missingContainers = new ArrayList<>();
containerHealthSchemaManager.getUnhealthyContainers(
- UnHealthyContainerStates.MISSING, 0, limit)
+ UnHealthyContainerStates.MISSING, 0L, Optional.empty(), limit)
.forEach(container -> {
long containerID = container.getContainerId();
try {
@@ -373,9 +374,12 @@ public Response getMissingContainers(
* eg UNDER_REPLICATED, MIS_REPLICATED, OVER_REPLICATED or
* MISSING. Passing null returns all containers.
* @param limit The limit of unhealthy containers to return.
- * @param batchNum The batch number (like "page number") of results to
return.
- * Passing 1, will return records 1 to limit. 2 will return
- * limit + 1 to 2 * limit, etc.
+ * @param maxContainerId Upper bound for container IDs to include
(exclusive).
+ * When specified, returns containers with IDs less
than this value
+ * in descending order. Use for backward pagination.
+ * @param minContainerId Lower bound for container IDs to include
(exclusive).
+ * When maxContainerId is not specified, returns
containers with IDs
+ * greater than this value in ascending order. Use for
forward pagination.
* @return {@link Response}
*/
@GET
@@ -384,10 +388,11 @@ public Response getUnhealthyContainers(
@PathParam("state") String state,
@DefaultValue(DEFAULT_FETCH_COUNT) @QueryParam(RECON_QUERY_LIMIT)
int limit,
- @DefaultValue(DEFAULT_BATCH_NUMBER)
- @QueryParam(RECON_QUERY_BATCH_PARAM) int batchNum) {
- int offset = Math.max(((batchNum - 1) * limit), 0);
-
+ @DefaultValue(PREV_CONTAINER_ID_DEFAULT_VALUE)
+ @QueryParam(RECON_QUERY_MAX_CONTAINER_ID) long maxContainerId,
+ @DefaultValue(PREV_CONTAINER_ID_DEFAULT_VALUE)
+ @QueryParam(RECON_QUERY_MIN_CONTAINER_ID) long minContainerId) {
+ Optional<Long> maxContainerIdOpt = maxContainerId > 0 ?
Optional.of(maxContainerId) : Optional.empty();
List<UnhealthyContainerMetadata> unhealthyMeta = new ArrayList<>();
List<UnhealthyContainersSummary> summary;
try {
@@ -401,7 +406,7 @@ public Response getUnhealthyContainers(
summary = containerHealthSchemaManager.getUnhealthyContainersSummary();
List<UnhealthyContainers> containers = containerHealthSchemaManager
- .getUnhealthyContainers(internalState, offset, limit);
+ .getUnhealthyContainers(internalState, minContainerId,
maxContainerIdOpt, limit);
// Filtering out EMPTY_MISSING and NEGATIVE_SIZE containers from the
response.
// These container states are not being inserted into the database as
they represent
@@ -434,6 +439,12 @@ public Response getUnhealthyContainers(
UnhealthyContainersResponse response =
new UnhealthyContainersResponse(unhealthyMeta);
+ if (!unhealthyMeta.isEmpty()) {
+
response.setFirstKey(unhealthyMeta.stream().map(UnhealthyContainerMetadata::getContainerID)
+ .min(Long::compareTo).orElse(0L));
+
response.setLastKey(unhealthyMeta.stream().map(UnhealthyContainerMetadata::getContainerID)
+ .max(Long::compareTo).orElse(0L));
+ }
for (UnhealthyContainersSummary s : summary) {
response.setSummaryCount(s.getContainerState(), s.getCount());
}
@@ -445,9 +456,12 @@ public Response getUnhealthyContainers(
* {@link org.apache.hadoop.ozone.recon.api.types.UnhealthyContainerMetadata}
* for all unhealthy containers.
* @param limit The limit of unhealthy containers to return.
- * @param batchNum The batch number (like "page number") of results to
return.
- * Passing 1, will return records 1 to limit. 2 will return
- * limit + 1 to 2 * limit, etc.
+ * @param maxContainerId Upper bound for container IDs to include
(exclusive).
+ * When specified, returns containers with IDs less
than this value
+ * in descending order. Use for backward pagination.
+ * @param minContainerId Lower bound for container IDs to include
(exclusive).
+ * When maxContainerId is not specified, returns
containers with IDs
+ * greater than this value in ascending order. Use for
forward pagination.
* @return {@link Response}
*/
@GET
@@ -455,9 +469,11 @@ public Response getUnhealthyContainers(
public Response getUnhealthyContainers(
@DefaultValue(DEFAULT_FETCH_COUNT) @QueryParam(RECON_QUERY_LIMIT)
int limit,
- @DefaultValue(DEFAULT_BATCH_NUMBER)
- @QueryParam(RECON_QUERY_BATCH_PARAM) int batchNum) {
- return getUnhealthyContainers(null, limit, batchNum);
+ @DefaultValue(PREV_CONTAINER_ID_DEFAULT_VALUE)
+ @QueryParam(RECON_QUERY_MAX_CONTAINER_ID) long maxContainerId,
+ @DefaultValue(PREV_CONTAINER_ID_DEFAULT_VALUE)
+ @QueryParam(RECON_QUERY_MIN_CONTAINER_ID) long minContainerId) {
+ return getUnhealthyContainers(null, limit, maxContainerId, minContainerId);
}
/**
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/UnhealthyContainersResponse.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/UnhealthyContainersResponse.java
index 07c1ca6819..350f9e8ced 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/UnhealthyContainersResponse.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/UnhealthyContainersResponse.java
@@ -55,6 +55,23 @@ public class UnhealthyContainersResponse {
@JsonProperty("replicaMismatchCount")
private long replicaMismatchCount = 0;
+ /**
+ * The smallest container ID in the current response batch.
+ * Used for pagination to determine the lower bound for the next page.
+ */
+ @JsonProperty("firstKey")
+ private long firstKey = 0;
+
+
+ /**
+ * The largest container ID in the current response batch.
+ * Used for pagination to determine the upper bound for the next page.
+ */
+ @JsonProperty("lastKey")
+ private long lastKey = 0;
+
+
+
/**
* A collection of unhealthy containers.
*/
@@ -108,7 +125,23 @@ public long getReplicaMismatchCount() {
return replicaMismatchCount;
}
+ public long getLastKey() {
+ return lastKey;
+ }
+
+ public long getFirstKey() {
+ return firstKey;
+ }
+
public Collection<UnhealthyContainerMetadata> getContainers() {
return containers;
}
+
+ public void setFirstKey(long firstKey) {
+ this.firstKey = firstKey;
+ }
+
+ public void setLastKey(long lastKey) {
+ this.lastKey = lastKey;
+ }
}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/persistence/ContainerHealthSchemaManager.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/persistence/ContainerHealthSchemaManager.java
index 84222fc6cc..b7b98ba1f9 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/persistence/ContainerHealthSchemaManager.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/persistence/ContainerHealthSchemaManager.java
@@ -23,18 +23,24 @@
import static
org.apache.ozone.recon.schema.generated.tables.UnhealthyContainersTable.UNHEALTHY_CONTAINERS;
import static org.jooq.impl.DSL.count;
+import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.sql.Connection;
+import java.util.Comparator;
import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
import org.apache.hadoop.ozone.recon.api.types.UnhealthyContainersSummary;
import org.apache.ozone.recon.schema.ContainerSchemaDefinition;
import
org.apache.ozone.recon.schema.ContainerSchemaDefinition.UnHealthyContainerStates;
import
org.apache.ozone.recon.schema.generated.tables.daos.UnhealthyContainersDao;
import
org.apache.ozone.recon.schema.generated.tables.pojos.UnhealthyContainers;
import
org.apache.ozone.recon.schema.generated.tables.records.UnhealthyContainersRecord;
+import org.jooq.Condition;
import org.jooq.Cursor;
import org.jooq.DSLContext;
+import org.jooq.OrderField;
import org.jooq.Record;
import org.jooq.SelectQuery;
import org.jooq.exception.DataAccessException;
@@ -67,32 +73,47 @@ public ContainerHealthSchemaManager(
* matching the given state will be returned.
* @param state Return only containers in this state, or all containers if
* null
- * @param offset The starting record to return in the result set. The first
- * record is at zero.
+ * @param minContainerId minimum containerId for filter
+ * @param maxContainerId maximum containerId for filter
* @param limit The total records to return
* @return List of unhealthy containers.
*/
public List<UnhealthyContainers> getUnhealthyContainers(
- UnHealthyContainerStates state, int offset, int limit) {
+ UnHealthyContainerStates state, Long minContainerId, Optional<Long>
maxContainerId, int limit) {
DSLContext dslContext = containerSchemaDefinition.getDSLContext();
SelectQuery<Record> query = dslContext.selectQuery();
query.addFrom(UNHEALTHY_CONTAINERS);
+ Condition containerCondition;
+ OrderField[] orderField;
+ if (maxContainerId.isPresent() && maxContainerId.get() > 0) {
+ containerCondition =
UNHEALTHY_CONTAINERS.CONTAINER_ID.lessThan(maxContainerId.get());
+ orderField = new OrderField[]{UNHEALTHY_CONTAINERS.CONTAINER_ID.desc(),
+ UNHEALTHY_CONTAINERS.CONTAINER_STATE.asc()};
+ } else {
+ containerCondition =
UNHEALTHY_CONTAINERS.CONTAINER_ID.greaterThan(minContainerId);
+ orderField = new OrderField[]{UNHEALTHY_CONTAINERS.CONTAINER_ID.asc(),
+ UNHEALTHY_CONTAINERS.CONTAINER_STATE.asc()};
+ }
if (state != null) {
if (state.equals(ALL_REPLICAS_BAD)) {
- query.addConditions(UNHEALTHY_CONTAINERS.CONTAINER_STATE
- .eq(UNDER_REPLICATED.toString()));
+
query.addConditions(containerCondition.and(UNHEALTHY_CONTAINERS.CONTAINER_STATE
+ .eq(UNDER_REPLICATED.toString())));
query.addConditions(UNHEALTHY_CONTAINERS.ACTUAL_REPLICA_COUNT.eq(0));
} else {
- query.addConditions(
- UNHEALTHY_CONTAINERS.CONTAINER_STATE.eq(state.toString()));
+
query.addConditions(containerCondition.and(UNHEALTHY_CONTAINERS.CONTAINER_STATE.eq(state.toString())));
}
+ } else {
+ // CRITICAL FIX: Apply pagination condition even when state is null
+ // This ensures proper pagination for the "get all unhealthy containers"
use case
+ query.addConditions(containerCondition);
}
- query.addOrderBy(UNHEALTHY_CONTAINERS.CONTAINER_ID.asc(),
- UNHEALTHY_CONTAINERS.CONTAINER_STATE.asc());
- query.addOffset(offset);
+
+ query.addOrderBy(orderField);
query.addLimit(limit);
- return query.fetchInto(UnhealthyContainers.class);
+ return query.fetchInto(UnhealthyContainers.class).stream()
+ .sorted(Comparator.comparingLong(UnhealthyContainers::getContainerId))
+ .collect(Collectors.toList());
}
/**
@@ -151,4 +172,19 @@ public void
insertUnhealthyContainerRecords(List<UnhealthyContainers> recs) {
}
}
+ /**
+ * Clear all unhealthy container records. This is primarily used for testing
+ * to ensure clean state between tests.
+ */
+ @VisibleForTesting
+ public void clearAllUnhealthyContainerRecords() {
+ DSLContext dslContext = containerSchemaDefinition.getDSLContext();
+ try {
+ dslContext.deleteFrom(UNHEALTHY_CONTAINERS).execute();
+ LOG.info("Cleared all unhealthy container records");
+ } catch (Exception e) {
+ LOG.info("Failed to clear unhealthy container records", e);
+ }
+ }
+
}
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestContainerEndpoint.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestContainerEndpoint.java
index 72376c7f92..a94ba618be 100644
---
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestContainerEndpoint.java
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestContainerEndpoint.java
@@ -804,7 +804,7 @@ void putContainerInfos(int num) throws IOException,
TimeoutException {
@Test
public void testUnhealthyContainers() throws IOException, TimeoutException {
- Response response = containerEndpoint.getUnhealthyContainers(1000, 1);
+ Response response = containerEndpoint.getUnhealthyContainers(1000, 0, 0);
UnhealthyContainersResponse responseObject =
(UnhealthyContainersResponse) response.getEntity();
@@ -823,7 +823,7 @@ public void testUnhealthyContainers() throws IOException,
TimeoutException {
uuid4 = newDatanode("host4", "127.0.0.4");
createUnhealthyRecords(5, 4, 3, 2, 1);
- response = containerEndpoint.getUnhealthyContainers(1000, 1);
+ response = containerEndpoint.getUnhealthyContainers(1000, 0, 0);
responseObject = (UnhealthyContainersResponse) response.getEntity();
assertEquals(5, responseObject.getMissingCount());
@@ -925,7 +925,7 @@ public void testUnhealthyContainersFilteredResponse()
// Initial empty response verification
Response response = containerEndpoint
- .getUnhealthyContainers(missing, 1000, 1);
+ .getUnhealthyContainers(missing, 1000, 0, 0);
UnhealthyContainersResponse responseObject =
(UnhealthyContainersResponse) response.getEntity();
@@ -947,7 +947,7 @@ public void testUnhealthyContainersFilteredResponse()
createNegativeSizeUnhealthyRecords(2); // For NEGATIVE_SIZE state
// Check for unhealthy containers
- response = containerEndpoint.getUnhealthyContainers(missing, 1000, 1);
+ response = containerEndpoint.getUnhealthyContainers(missing, 1000, 0, 0);
responseObject = (UnhealthyContainersResponse) response.getEntity();
@@ -972,14 +972,14 @@ public void testUnhealthyContainersFilteredResponse()
// Check for empty missing containers, should return zero
Response filteredEmptyMissingResponse = containerEndpoint
- .getUnhealthyContainers(emptyMissing, 1000, 1);
+ .getUnhealthyContainers(emptyMissing, 1000, 0, 0);
responseObject = (UnhealthyContainersResponse)
filteredEmptyMissingResponse.getEntity();
records = responseObject.getContainers();
assertEquals(0, records.size());
// Check for negative size containers, should return zero
Response filteredNegativeSizeResponse = containerEndpoint
- .getUnhealthyContainers(negativeSize, 1000, 1);
+ .getUnhealthyContainers(negativeSize, 1000, 0, 0);
responseObject = (UnhealthyContainersResponse)
filteredNegativeSizeResponse.getEntity();
records = responseObject.getContainers();
assertEquals(0, records.size());
@@ -988,30 +988,43 @@ public void testUnhealthyContainersFilteredResponse()
@Test
public void testUnhealthyContainersInvalidState() {
WebApplicationException e = assertThrows(WebApplicationException.class,
- () -> containerEndpoint.getUnhealthyContainers("invalid", 1000, 1));
+ () -> containerEndpoint.getUnhealthyContainers("invalid", 1000, 0, 0));
assertEquals("HTTP 400 Bad Request", e.getMessage());
}
@Test
public void testUnhealthyContainersPaging()
throws IOException, TimeoutException {
- putContainerInfos(6);
+
+ // Clear any existing unhealthy container records from previous tests
+ containerHealthSchemaManager.clearAllUnhealthyContainerRecords();
+ // Create containers for all IDs that will be used in unhealthy records
+ // createUnhealthyRecords(5, 4, 3, 2) will create records for containers
1-14
+ // So we need to create 14 containers instead of just 6
+ putContainerInfos(14); // Changed from 6 to 14
uuid1 = newDatanode("host1", "127.0.0.1");
uuid2 = newDatanode("host2", "127.0.0.2");
uuid3 = newDatanode("host3", "127.0.0.3");
uuid4 = newDatanode("host4", "127.0.0.4");
createUnhealthyRecords(5, 4, 3, 2, 0);
+
+ // Get first batch with no pagination (prevStartKey=0, prevLastKey=0)
UnhealthyContainersResponse firstBatch =
(UnhealthyContainersResponse) containerEndpoint.getUnhealthyContainers(
- 3, 1).getEntity();
+ 3, 0, 0).getEntity();
assertTrue(firstBatch.getContainers().stream()
.flatMap(containerMetadata -> containerMetadata.getReplicas().stream()
.map(ContainerHistory::getState))
.allMatch(s -> s.equals("UNHEALTHY")));
+ // For pagination, use the last container ID from the first batch as
prevLastKey
+ long lastContainerIdFromFirstBatch = firstBatch.getContainers().stream()
+ .map(i -> i.getContainerID()).max(Long::compareTo).get();
+
+ // Get second batch using correct pagination parameters
UnhealthyContainersResponse secondBatch =
(UnhealthyContainersResponse) containerEndpoint.getUnhealthyContainers(
- 3, 2).getEntity();
+ 3, 0, lastContainerIdFromFirstBatch).getEntity();
ArrayList<UnhealthyContainerMetadata> records
= new ArrayList<>(firstBatch.getContainers());
@@ -1019,7 +1032,6 @@ public void testUnhealthyContainersPaging()
assertEquals(1L, records.get(0).getContainerID());
assertEquals(2L, records.get(1).getContainerID());
assertEquals(3L, records.get(2).getContainerID());
-
records
= new ArrayList<>(secondBatch.getContainers());
assertEquals(3, records.size());
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/fsck/TestContainerHealthTask.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/fsck/TestContainerHealthTask.java
index fc659b49fd..ca902ea378 100644
---
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/fsck/TestContainerHealthTask.java
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/fsck/TestContainerHealthTask.java
@@ -41,6 +41,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
@@ -225,7 +226,7 @@ public void testRun() throws Exception {
List<UnhealthyContainers> unhealthyContainers =
containerHealthSchemaManager.getUnhealthyContainers(
- ALL_REPLICAS_BAD, 0, Integer.MAX_VALUE);
+ ALL_REPLICAS_BAD, 0L, Optional.empty(), Integer.MAX_VALUE);
assertEquals(1, unhealthyContainers.size());
assertEquals(2L,
unhealthyContainers.get(0).getContainerId().longValue());
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]