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

ashishkumar50 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 d14bc0f5fc1 HDDS-15637. Container Replica Debugger Tool improvements 
and minor bug fixes (#10574)
d14bc0f5fc1 is described below

commit d14bc0f5fc10caad177c144c3648a7c10d7a860f
Author: sreejasahithi <[email protected]>
AuthorDate: Wed Jul 8 10:31:48 2026 +0530

    HDDS-15637. Container Replica Debugger Tool improvements and minor bug 
fixes (#10574)
---
 .../logs/container/ContainerLogController.java     |  3 +
 .../debug/logs/container/ContainerLogParser.java   | 16 +++++-
 .../container/DuplicateOpenContainersCommand.java  |  9 ++-
 .../ozone/debug/logs/container/ListContainers.java | 33 ++++++++---
 .../container/utils/ContainerDatanodeDatabase.java | 63 ++++++++++++---------
 .../container/utils/ContainerLogFileParser.java    | 65 +++++++++++++++-------
 .../debug/logs/container/utils/SQLDBConstants.java | 58 +++++++++++--------
 7 files changed, 164 insertions(+), 83 deletions(-)

diff --git 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/ContainerLogController.java
 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/ContainerLogController.java
index 1a6cdafea63..05bc9d59cae 100644
--- 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/ContainerLogController.java
+++ 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/ContainerLogController.java
@@ -75,6 +75,9 @@ public Path resolveDbPath() {
         throw new IllegalArgumentException("The parent directory of the 
provided database " +
             "path does not exist: " + parentDir);
       }
+      if (!Files.exists(resolvedPath) || !Files.isRegularFile(resolvedPath)) {
+        throw new IllegalArgumentException("Database file does not exist: " + 
resolvedPath);
+      }
     }
 
     return resolvedPath;
diff --git 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/ContainerLogParser.java
 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/ContainerLogParser.java
index cac2518b381..1972e87914f 100644
--- 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/ContainerLogParser.java
+++ 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/ContainerLogParser.java
@@ -90,7 +90,21 @@ public Void call() throws Exception {
 
     cdd.insertLatestContainerLogData();
     cdd.createIndexes();
-    out().println("Successfully parsed the log files and updated the 
respective tables");
+
+    int failures = parser.getParseFailureCount();
+    int successes = parser.getParseSuccessCount();
+    if (successes == 0 && failures == 0) {
+      err().println("No container log files were found to parse (expected 
dn-container[...].log.<datanodeId>).");
+      out().println("Database tables were created but are empty.");
+    } else if (failures == 0) {
+      out().println("Successfully parsed the log files and updated the 
respective tables");
+    } else if (successes == 0) {
+      err().println(failures + " log file(s) could not be parsed. No log data 
was loaded into the database.");
+      out().println("Database tables were created but are empty.");
+    } else {
+      err().println(failures + " log file(s) could not be parsed and were 
excluded.");
+      out().println("Database tables were updated from successfully parsed 
files.");
+    }
 
     return null;
   }
diff --git 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/DuplicateOpenContainersCommand.java
 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/DuplicateOpenContainersCommand.java
index a0fb8371ecd..8ca07fa3de8 100644
--- 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/DuplicateOpenContainersCommand.java
+++ 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/DuplicateOpenContainersCommand.java
@@ -19,7 +19,9 @@
 
 import java.nio.file.Path;
 import java.util.concurrent.Callable;
+import org.apache.hadoop.hdds.cli.AbstractSubcommand;
 import 
org.apache.hadoop.ozone.debug.logs.container.utils.ContainerDatanodeDatabase;
+import org.apache.hadoop.ozone.shell.ListLimitOptions;
 import picocli.CommandLine;
 
 /**
@@ -31,8 +33,11 @@
     description = "List all containers which have duplicate open states." +
         "Outputs the container ID along with the count of OPEN state entries."
 )
-public class DuplicateOpenContainersCommand implements Callable<Void> {
+public class DuplicateOpenContainersCommand extends AbstractSubcommand 
implements Callable<Void> {
 
+  @CommandLine.Mixin
+  private ListLimitOptions listOptions;
+  
   @CommandLine.ParentCommand
   private ContainerLogController parent;
 
@@ -41,7 +46,7 @@ public Void call() throws Exception {
     Path dbPath = parent.resolveDbPath();
 
     ContainerDatanodeDatabase cdd = new 
ContainerDatanodeDatabase(dbPath.toString());
-    cdd.findDuplicateOpenContainer();
+    cdd.findDuplicateOpenContainer(listOptions.getLimit());
 
     return null;
   }
diff --git 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/ListContainers.java
 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/ListContainers.java
index f4c72c720f1..1292b1bfa3a 100644
--- 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/ListContainers.java
+++ 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/ListContainers.java
@@ -17,16 +17,10 @@
 
 package org.apache.hadoop.ozone.debug.logs.container;
 
-import static 
org.apache.hadoop.hdds.scm.container.ContainerHealthState.OVER_REPLICATED;
-import static 
org.apache.hadoop.hdds.scm.container.ContainerHealthState.QUASI_CLOSED_STUCK;
-import static 
org.apache.hadoop.hdds.scm.container.ContainerHealthState.UNDER_REPLICATED;
-import static 
org.apache.hadoop.hdds.scm.container.ContainerHealthState.UNHEALTHY;
-
 import java.nio.file.Path;
 import java.util.concurrent.Callable;
 import org.apache.hadoop.hdds.cli.AbstractSubcommand;
 import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
-import org.apache.hadoop.hdds.scm.container.ContainerHealthState;
 import 
org.apache.hadoop.ozone.debug.logs.container.utils.ContainerDatanodeDatabase;
 import org.apache.hadoop.ozone.shell.ListLimitOptions;
 import picocli.CommandLine;
@@ -53,12 +47,23 @@ public class ListContainers extends AbstractSubcommand 
implements Callable<Void>
 
   private static final class ExclusiveOptions {
     @CommandLine.Option(names = {"--lifecycle"},
-        description = "Life cycle state of the container.")
+        description = "Replicas whose latest state equals the given value are 
shown. " +
+            "Prints one row per matching replica.")
     private HddsProtos.LifeCycleState lifecycleState;
 
     @CommandLine.Option(names = {"--health"},
-        description = "Health state of the container.")
-    private ContainerHealthState healthState;
+        description = "Log-derived health filter.%n"
+            + " UNDER_REPLICATED: containers where healthy replica count 
(latest state of replica not UNHEALTHY or"
+            + "  DELETED) is below the configured replication factor. Count = 
total active (non-DELETED) replicas.%n"
+            + " OVER_REPLICATED: containers where active replica count exceeds 
configured replication factor and"
+            + "  healthy replica count is at least equal to configured 
replication factor. Count = total active"
+            + "  (non-DELETED) replicas.%n"
+            + " UNHEALTHY: containers where every active replica is UNHEALTHY 
(no healthy replicas remain).%n"
+            + "  Count = number of UNHEALTHY replicas.%n"
+            + " QUASI_CLOSED_STUCK: approximate log heuristic only (not SCM 
quasi-closed stuck): containers"
+            + " with at least three datanodes whose QUASI_CLOSED log entry is 
not superseded by CLOSED or"
+            + " DELETED on that datanode.")
+    private LogHealthFilter healthState;
   }
 
   @Override
@@ -89,4 +94,14 @@ public Void call() throws Exception {
     
     return null;
   }
+  
+  /**
+   * Log-derived health filters supported by {@code list --health}.
+   */
+  enum LogHealthFilter {
+    UNDER_REPLICATED,
+    OVER_REPLICATED,
+    UNHEALTHY,
+    QUASI_CLOSED_STUCK
+  }
 }
diff --git 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/utils/ContainerDatanodeDatabase.java
 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/utils/ContainerDatanodeDatabase.java
index 60e764237fb..62ce8771702 100644
--- 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/utils/ContainerDatanodeDatabase.java
+++ 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/utils/ContainerDatanodeDatabase.java
@@ -304,7 +304,7 @@ public void listContainersByState(String state, Integer 
limit) throws SQLExcepti
 
           while (rs.next()) {
             if (limitProvided && count >= limit) {
-              out.println("Note: There might be more containers. Use -all 
option to list all entries");
+              out.println("Note: There might be more replica rows. Use --all 
option to list all entries");
               break;
             }
             String timestamp = rs.getString("timestamp");
@@ -320,9 +320,9 @@ public void listContainersByState(String state, Integer 
limit) throws SQLExcepti
           }
           
           if (count == 0) {
-            out.printf("No containers found for state: %s%n", state);
+            out.printf("No replicas found with latest state %s%n", state);
           } else {
-            out.printf("Number of containers listed: %d%n", count);
+            out.printf("Number of replica rows listed: %d%n", count);
           }
         }
       }
@@ -410,6 +410,7 @@ private void analyzeContainerHealth(Long containerID,
     Set<String> unhealthyReplicas = new HashSet<>();
     Set<String> closedReplicas = new HashSet<>();
     Set<String> openReplicas = new HashSet<>();
+    Set<String> closingReplicas = new HashSet<>();
     Set<String> quasiclosedReplicas = new HashSet<>();
     Set<String> deletedReplicas = new HashSet<>();
     Set<Long> bcsids = new HashSet<>();
@@ -444,6 +445,7 @@ private void analyzeContainerHealth(Long containerID,
           otherTimestamps.add(stateTimestamp);
           break;
         case CLOSING:
+          closingReplicas.add(datanodeId);
           otherTimestamps.add(stateTimestamp);
           break;
         case CLOSED:
@@ -474,7 +476,7 @@ private void analyzeContainerHealth(Long containerID,
       out.println("Container " + containerID + " has MISMATCHED REPLICATION as 
there are multiple" +
           " CLOSED containers with varying BCSIDs.");
     } else if (closedCount == DEFAULT_REPLICATION_FACTOR && allClosedNewer) {
-      out.println("Container " + containerID + " has enough replicas.");
+      out.println("Container " + containerID + " has enough closed replicas.");
     } else if (closedCount > DEFAULT_REPLICATION_FACTOR && allClosedNewer) {
       out.println("Container " + containerID + " is OVER-REPLICATED.");
     } else if (closedCount < DEFAULT_REPLICATION_FACTOR && closedCount != 0 && 
allClosedNewer) {
@@ -499,6 +501,12 @@ private void analyzeContainerHealth(Long containerID,
         out.println("Container " + containerID + " has enough replicas.");
       } 
     }
+
+    out.println();
+    out.println("Log summary (latest per datanode, Replication Factor=" + 
DEFAULT_REPLICATION_FACTOR + "):");
+    out.printf("  CLOSED=%d, QUASI_CLOSED=%d, CLOSING=%d, OPEN=%d, DELETED=%d, 
UNHEALTHY=%d%n",
+        closedReplicas.size(), quasiclosedReplicas.size(), 
closingReplicas.size(), openReplicas.size(),
+        deletedReplicas.size(), unhealthyReplicas.size());
   }
 
   /**
@@ -564,8 +572,9 @@ private List<DatanodeContainerInfo> 
getContainerLogData(Long containerID, Connec
     return logEntries;
   }
 
-  public void findDuplicateOpenContainer() throws SQLException {
+  public void findDuplicateOpenContainer(Integer limit) throws SQLException {
     String sql = SQLDBConstants.SELECT_DISTINCT_CONTAINER_IDS_QUERY;
+    boolean limitProvided = limit != Integer.MAX_VALUE;
 
     try (Connection connection = getConnection()) {
 
@@ -576,8 +585,11 @@ public void findDuplicateOpenContainer() throws 
SQLException {
         while (resultSet.next()) {
           Long containerID = resultSet.getLong("container_id");
           List<DatanodeContainerInfo> logEntries = 
getContainerLogDataForOpenContainers(containerID, connection);
-          boolean hasIssue = checkForMultipleOpenStates(logEntries);
-          if (hasIssue) {
+          if (checkForMultipleOpenStates(logEntries)) {
+            if (limitProvided && count >= limit) {
+              err.println("Note: There might be more containers. Use --all 
option to list all entries.");
+              break;
+            }
             int openStateCount = (int) logEntries.stream()
                 .filter(entry -> "OPEN".equalsIgnoreCase(entry.getState()))
                 .count();
@@ -624,37 +636,36 @@ private List<DatanodeContainerInfo> 
getContainerLogDataForOpenContainers(Long co
    */
   
   public void listReplicatedContainers(String overOrUnder, Integer limit) 
throws SQLException {
-    String operator;
-    if ("OVER_REPLICATED".equalsIgnoreCase(overOrUnder)) {
-      operator = ">";
+    String query;
+    boolean overReplicated = "OVER_REPLICATED".equalsIgnoreCase(overOrUnder);
+    if (overReplicated) {
+      query = SQLDBConstants.SELECT_OVER_REPLICATED_CONTAINERS;
     } else if ("UNDER_REPLICATED".equalsIgnoreCase(overOrUnder)) {
-      operator = "<";
+      query = SQLDBConstants.SELECT_UNDER_REPLICATED_CONTAINERS;
     } else {
       err.println("Invalid type. Use OVER_REPLICATED or UNDER_REPLICATED.");
       return;
     }
-    
-    String rawQuery = SQLDBConstants.SELECT_REPLICATED_CONTAINERS;
-
-    if (!rawQuery.contains("{operator}")) {
-      err.println("Query not defined correctly.");
-      return;
-    }
-
-    String finalQuery = rawQuery.replace("{operator}", operator);
 
     boolean limitProvided = limit != Integer.MAX_VALUE;
     if (limitProvided) {
-      finalQuery += " LIMIT ?";
+      query += " LIMIT ?";
     }
 
     try (Connection connection = getConnection();
-         PreparedStatement pstmt = connection.prepareStatement(finalQuery)) {
+         PreparedStatement pstmt = connection.prepareStatement(query)) {
 
-      pstmt.setInt(1, DEFAULT_REPLICATION_FACTOR);
-      
-      if (limitProvided) {
-        pstmt.setInt(2, limit + 1);
+      if (overReplicated) {
+        pstmt.setInt(1, DEFAULT_REPLICATION_FACTOR);
+        pstmt.setInt(2, DEFAULT_REPLICATION_FACTOR);
+        if (limitProvided) {
+          pstmt.setInt(3, limit + 1);
+        }
+      } else {
+        pstmt.setInt(1, DEFAULT_REPLICATION_FACTOR);
+        if (limitProvided) {
+          pstmt.setInt(2, limit + 1);
+        }
       }
 
       try (ResultSet rs = pstmt.executeQuery()) {
diff --git 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/utils/ContainerLogFileParser.java
 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/utils/ContainerLogFileParser.java
index f0f6649b305..457515011b1 100644
--- 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/utils/ContainerLogFileParser.java
+++ 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/utils/ContainerLogFileParser.java
@@ -26,10 +26,13 @@
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -42,18 +45,33 @@ public class ContainerLogFileParser {
 
   private static final int MAX_OBJ_IN_LIST = 5000;
 
-  private static final String LOG_FILE_MARKER = ".log.";
+  /**
+   * Matches {@code dn-container.log.<datanodeId>} and
+   * {@code dn-container-<roll>.log.<datanodeId>}.
+   */
+  private static final Pattern CONTAINER_LOG_FILE_PATTERN =
+      Pattern.compile("^dn-container(?:-(.+))?\\.log\\.(.+)$");
   private static final String LOG_LINE_SPLIT_REGEX = " \\| ";
   private static final String KEY_VALUE_SPLIT_REGEX = "=";
   private static final String KEY_ID = "ID";
   private static final String KEY_BCSID = "BCSID";
   private static final String KEY_STATE = "State";
   private static final String KEY_INDEX = "Index";
-  private final AtomicBoolean hasErrorOccurred = new AtomicBoolean(false);
+  private final AtomicInteger parseSuccessCount = new AtomicInteger(0);
+  private final AtomicInteger parseFailureCount = new AtomicInteger(0);
+
+  public int getParseSuccessCount() {
+    return parseSuccessCount.get();
+  }
+
+  public int getParseFailureCount() {
+    return parseFailureCount.get();
+  }
   
   /**
    * Scans the specified log directory, processes each file in a separate 
thread.
-   * Expects each log filename to follow the format: dn-container-<roll over 
number>.log.<datanodeId>
+   * Expects each log filename to follow the format: 
dn-container.log.<datanodeId> or
+   * dn-container-<roll over number>.log.<datanodeId>
    *
    * @param logDirectoryPath Path to the directory containing container log 
files.
    * @param dbstore Database object used to persist parsed container data.
@@ -61,7 +79,7 @@ public class ContainerLogFileParser {
    */
 
   public void processLogEntries(String logDirectoryPath, 
ContainerDatanodeDatabase dbstore, int threadCount)
-      throws SQLException, IOException, InterruptedException {
+      throws IOException, InterruptedException {
     try (Stream<Path> paths = Files.walk(Paths.get(logDirectoryPath))) {
 
       List<Path> files = 
paths.filter(Files::isRegularFile).collect(Collectors.toList());
@@ -73,18 +91,14 @@ public void processLogEntries(String logDirectoryPath, 
ContainerDatanodeDatabase
         Path fileNamePath = file.getFileName();
         String fileName = (fileNamePath != null) ? fileNamePath.toString() : 
"";
         
-        int pos = fileName.indexOf(LOG_FILE_MARKER);
-        if (pos == -1) {
-          System.out.println("Filename format is incorrect (missing .log.): " 
+ fileName);
-          continue;
-        }
-        
-        String datanodeId = fileName.substring(pos + 5);
-        
-        if (datanodeId.isEmpty()) {
-          System.out.println("Filename format is incorrect, datanodeId is 
missing or empty: " + fileName);
+        Optional<String> datanodeIdOpt = extractDatanodeId(fileName);
+        if (!datanodeIdOpt.isPresent()) {
+          System.out.println("Skipping non-container log file (expected 
dn-container[...].log.<datanodeId>): "
+              + fileName);
+          latch.countDown();
           continue;
         }
+        String datanodeId = datanodeIdOpt.get();
         
         executorService.submit(() -> {
 
@@ -92,10 +106,11 @@ public void processLogEntries(String logDirectoryPath, 
ContainerDatanodeDatabase
           try {
             System.out.println(threadName + " is starting to process file: " + 
file.toString());
             processFile(file.toString(), dbstore, datanodeId);
+            parseSuccessCount.incrementAndGet();
           } catch (Exception e) {
+            parseFailureCount.incrementAndGet();
             System.err.println("Thread " + threadName + " is stopping to 
process the file: " + file.toString() +
-                " due to SQLException: " + e.getMessage());
-            hasErrorOccurred.set(true);
+                " due to : " + e.getMessage());
           } finally {
             try {
               latch.countDown();
@@ -110,12 +125,16 @@ public void processLogEntries(String logDirectoryPath, 
ContainerDatanodeDatabase
       latch.await();
 
       executorService.shutdown();
-      
-      if (hasErrorOccurred.get()) {
-        throw new SQLException("Log file processing failed.");
-      }
+    }
+  }
 
+  static Optional<String> extractDatanodeId(String fileName) {
+    Matcher matcher = CONTAINER_LOG_FILE_PATTERN.matcher(fileName);
+    if (!matcher.matches()) {
+      return Optional.empty();
     }
+    String datanodeId = matcher.group(2);
+    return datanodeId.isEmpty() ? Optional.empty() : Optional.of(datanodeId);
   }
 
   /**
@@ -135,6 +154,10 @@ private void processFile(String logFilePath, 
ContainerDatanodeDatabase dbstore,
       String line;
       while ((line = reader.readLine()) != null) {
         String[] parts = line.split(LOG_LINE_SPLIT_REGEX);
+        if (parts.length < 2) {
+          System.err.println("Skipping malformed log line: " + line);
+          continue;
+        }
         String timestamp = parts[0].trim();
         String logLevel = parts[1].trim();
         String id = null, index = null;
diff --git 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/utils/SQLDBConstants.java
 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/utils/SQLDBConstants.java
index 0e159a1bbe9..4d76c06684c 100644
--- 
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/utils/SQLDBConstants.java
+++ 
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/logs/container/utils/SQLDBConstants.java
@@ -86,31 +86,41 @@ public final class SQLDBConstants {
   public static final String CREATE_DCL_STATE_CONTAINER_DATANODE_TIME_INDEX =
       "CREATE INDEX IF NOT EXISTS idx_dcl_state_container_datanode_time " +
           "ON DatanodeContainerLogTable(container_state, container_id, 
datanode_id, timestamp DESC);";
-  public static final String SELECT_REPLICATED_CONTAINERS =
-          "SELECT container_id, COUNT(DISTINCT datanode_id) AS 
replica_count\n" +
-                  "FROM ContainerLogTable\n" +
-                  "WHERE latest_state != '" + DELETED_STATE + "'\n" +
-                  " GROUP BY container_id\n" +
-                  "HAVING COUNT(DISTINCT datanode_id) {operator} ?";
+
+  private static final String REPLICA_COUNTS_CTE =
+      "  SELECT\n" +
+      "    container_id,\n" +
+      "    SUM(CASE WHEN latest_state != '" + UNHEALTHY_STATE + "' THEN 1 ELSE 
0 END) AS count_a,\n" +
+      "    SUM(CASE WHEN latest_state = '" + UNHEALTHY_STATE + "' THEN 1 ELSE 
0 END) AS count_b,\n" +
+      "    COUNT(DISTINCT datanode_id) AS count_c\n" +
+      "  FROM ContainerLogTable\n" +
+      "  WHERE latest_state != '" + DELETED_STATE + "'\n" +
+      "  GROUP BY container_id\n";
+  
+  public static final String SELECT_UNDER_REPLICATED_CONTAINERS =
+      "WITH replica_counts AS (\n" +
+          REPLICA_COUNTS_CTE +
+          ")\n" +
+          "SELECT container_id, count_c AS replica_count\n" +
+          "FROM replica_counts\n" +
+          "WHERE count_a < ?\n" +
+          "ORDER BY container_id";
+  public static final String SELECT_OVER_REPLICATED_CONTAINERS =
+      "WITH replica_counts AS (\n" +
+          REPLICA_COUNTS_CTE +
+          ")\n" +
+          "SELECT container_id, count_c AS replica_count\n" +
+          "FROM replica_counts\n" +
+          "WHERE count_c > ? AND count_a >= ?\n" +
+          "ORDER BY container_id";
   public static final String SELECT_UNHEALTHY_CONTAINERS =
-      "SELECT u.container_id, COUNT(*) AS unhealthy_replica_count\n" +
-          "FROM (\n" +
-          "    SELECT container_id, datanode_id, MAX(timestamp) AS 
latest_unhealthy_timestamp\n" +
-          "    FROM DatanodeContainerLogTable\n" +
-          "    WHERE container_state = '" + UNHEALTHY_STATE + "'\n" +
-          "    GROUP BY container_id, datanode_id\n" +
-          ") AS u\n" +
-          "LEFT JOIN (\n" +
-          "    SELECT container_id, datanode_id, MAX(timestamp) AS 
latest_closed_timestamp\n" +
-          "    FROM DatanodeContainerLogTable\n" +
-          "    WHERE container_state IN ('" + CLOSED_STATE + "', '" + 
DELETED_STATE + "')\n" +
-          "    GROUP BY container_id, datanode_id\n" +
-          ") AS c\n" +
-          "ON u.container_id = c.container_id AND u.datanode_id = 
c.datanode_id\n" +
-          "WHERE c.latest_closed_timestamp IS NULL \n" +
-          "   OR u.latest_unhealthy_timestamp > c.latest_closed_timestamp\n" +
-              "GROUP BY u.container_id\n" +
-              "ORDER BY u.container_id";
+      "WITH replica_counts AS (\n" +
+          REPLICA_COUNTS_CTE +
+          ")\n" +
+          "SELECT container_id, count_b AS unhealthy_replica_count\n" +
+          "FROM replica_counts\n" +
+          "WHERE count_b = count_c AND count_c > 0\n" +
+          "ORDER BY container_id";
   public static final String SELECT_QUASI_CLOSED_STUCK_CONTAINERS =
       "WITH quasi_closed_replicas AS ( " +
           "    SELECT container_id, datanode_id, MAX(timestamp) AS 
latest_quasi_closed_timestamp\n" +


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to