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

errose28 pushed a commit to branch HDDS-14496-zdu
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/HDDS-14496-zdu by this push:
     new 37874d15574 HDDS-15549. Recon's INITIAL_VERSION should not have an 
upgrade action (#10935)
37874d15574 is described below

commit 37874d15574005d8a1ac0f81322e6214687f0f86
Author: Ethan Rose <[email protected]>
AuthorDate: Mon Aug 17 16:09:08 2026 -0400

    HDDS-15549. Recon's INITIAL_VERSION should not have an upgrade action 
(#10935)
---
 .../upgrade/InitialConstraintUpgradeAction.java    |  39 ----
 .../upgrade/ReconTaskStatusTableUpgradeAction.java |   6 +-
 .../TestInitialConstraintUpgradeAction.java        | 199 ---------------------
 .../TestReconTaskStatusTableUpgradeAction.java     |  29 +++
 ...estUnhealthyContainerReplicaMismatchAction.java |  29 +++
 5 files changed, 63 insertions(+), 239 deletions(-)

diff --git 
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/InitialConstraintUpgradeAction.java
 
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/InitialConstraintUpgradeAction.java
deleted file mode 100644
index ffcf89768f2..00000000000
--- 
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/InitialConstraintUpgradeAction.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hadoop.ozone.recon.upgrade;
-
-import static 
org.apache.hadoop.ozone.recon.upgrade.ReconVersion.INITIAL_VERSION;
-
-import java.sql.SQLException;
-import javax.sql.DataSource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Upgrade action for the INITIAL schema version, which manages constraints
- * for the UNHEALTHY_CONTAINERS table.
- */
-@ReconUpgradeActionForVersion(version = INITIAL_VERSION)
-public class InitialConstraintUpgradeAction implements ReconUpgradeAction {
-  private static final Logger LOG = 
LoggerFactory.getLogger(InitialConstraintUpgradeAction.class);
-
-  @Override
-  public void execute(DataSource source) throws SQLException {
-    ReconUpgradeAction.updateUnhealthyContainerStatesConstraint(source, LOG);
-  }
-}
diff --git 
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReconTaskStatusTableUpgradeAction.java
 
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReconTaskStatusTableUpgradeAction.java
index f8a5a98a695..9deabc163ea 100644
--- 
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReconTaskStatusTableUpgradeAction.java
+++ 
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/ReconTaskStatusTableUpgradeAction.java
@@ -34,9 +34,11 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * Upgrade action for TASK_STATUS_STATISTICS feature layout change, which adds
+ * Upgrade action for TASK_STATUS_STATISTICS version, which adds
  * <code>last_task_run_status</code> and <code>current_task_run_status</code> 
columns to
  * {@link ReconTaskSchemaDefinition} in case it is missing .
+ * <p>
+ * It also applies the UNHEALTHY_CONTAINERS check constraint which must be run 
with Recon's first version increase.
  */
 @ReconUpgradeActionForVersion(version = ReconVersion.TASK_STATUS_STATISTICS)
 public class ReconTaskStatusTableUpgradeAction implements ReconUpgradeAction {
@@ -73,6 +75,8 @@ private void setColumnAsNonNullableIfNeeded(Connection conn, 
DSLContext dslConte
 
   @Override
   public void execute(DataSource dataSource) throws DataAccessException, 
SQLException {
+    ReconUpgradeAction.updateUnhealthyContainerStatesConstraint(dataSource, 
LOG);
+
     try (Connection conn = dataSource.getConnection()) {
       if (!TABLE_EXISTS_CHECK.test(conn, RECON_TASK_STATUS_TABLE_NAME)) {
         return;
diff --git 
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestInitialConstraintUpgradeAction.java
 
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestInitialConstraintUpgradeAction.java
deleted file mode 100644
index 5b90e50a4ce..00000000000
--- 
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestInitialConstraintUpgradeAction.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hadoop.ozone.recon.upgrade;
-
-import static 
org.apache.ozone.recon.schema.ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME;
-import static org.apache.ozone.recon.schema.SqlDbUtils.constraintExists;
-import static org.jooq.impl.DSL.field;
-import static org.jooq.impl.DSL.name;
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import javax.sql.DataSource;
-import org.apache.hadoop.ozone.recon.persistence.AbstractReconSqlDBTest;
-import org.apache.hadoop.ozone.recon.scm.ReconStorageContainerManagerFacade;
-import org.apache.ozone.recon.schema.ContainerSchemaDefinition;
-import org.jooq.DSLContext;
-import org.jooq.impl.DSL;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-/**
- * Test class for InitialConstraintUpgradeAction.
- */
-public class TestInitialConstraintUpgradeAction extends AbstractReconSqlDBTest 
{
-
-  private InitialConstraintUpgradeAction upgradeAction;
-  private DSLContext dslContext;
-  private ReconStorageContainerManagerFacade mockScmFacade;
-
-  @BeforeEach
-  public void setUp() throws SQLException {
-    // Initialize the DSLContext
-    dslContext = getDslContext();
-
-    // Initialize the upgrade action
-    upgradeAction = new InitialConstraintUpgradeAction();
-
-    // Mock the SCM facade to provide the DataSource
-    mockScmFacade = mock(ReconStorageContainerManagerFacade.class);
-    DataSource dataSource = getInjector().getInstance(DataSource.class);
-    when(mockScmFacade.getDataSource()).thenReturn(dataSource);
-
-    // Check if the table already exists
-    try (Connection conn = dataSource.getConnection()) {
-      DatabaseMetaData dbMetaData = conn.getMetaData();
-      ResultSet tables = dbMetaData.getTables(null, null, 
UNHEALTHY_CONTAINERS_TABLE_NAME, null);
-      if (!tables.next()) {
-        // Create the initial table if it does not exist
-        dslContext.createTable(UNHEALTHY_CONTAINERS_TABLE_NAME)
-            .column("container_id", org.jooq.impl.SQLDataType.BIGINT
-                .nullable(false))
-            .column("container_state", org.jooq.impl.SQLDataType.VARCHAR(16)
-                .nullable(false))
-            .constraint(DSL.constraint("pk_container_id")
-                .primaryKey("container_id", "container_state"))
-            .execute();
-      }
-    }
-  }
-
-  @Test
-  public void testExecuteIsIdempotent() throws SQLException {
-    DataSource dataSource = getInjector().getInstance(DataSource.class);
-    upgradeAction.execute(dataSource);
-    try (Connection conn = dataSource.getConnection()) {
-      assertTrue(constraintExists(conn, UNHEALTHY_CONTAINERS_TABLE_NAME,
-          UNHEALTHY_CONTAINERS_TABLE_NAME + "ck1"));
-    }
-    assertDoesNotThrow(() -> upgradeAction.execute(dataSource));
-  }
-
-  @Test
-  public void testUpgradeAppliesConstraintModificationForAllStates() throws 
SQLException {
-    // Run the upgrade action
-    upgradeAction.execute(mockScmFacade.getDataSource());
-
-    // Iterate over all valid states and insert records
-    for (ContainerSchemaDefinition.UnHealthyContainerStates state :
-        ContainerSchemaDefinition.UnHealthyContainerStates.values()) {
-      dslContext.insertInto(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME))
-          .columns(
-              field(name("container_id")),
-              field(name("container_state")),
-              field(name("in_state_since")),
-              field(name("expected_replica_count")),
-              field(name("actual_replica_count")),
-              field(name("replica_delta")),
-              field(name("reason"))
-          )
-          .values(
-              System.currentTimeMillis(), // Unique container_id for each 
record
-              state.name(), System.currentTimeMillis(), 3, 2, 1, "Replica 
count mismatch"
-          )
-          .execute();
-    }
-
-    // Verify that the number of inserted records matches the number of enum 
values
-    int count = 
dslContext.fetchCount(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME));
-    
assertEquals(ContainerSchemaDefinition.UnHealthyContainerStates.values().length,
-        count, "Expected one record for each valid state");
-
-    // Try inserting an invalid state (should fail due to constraint)
-    assertThrows(org.jooq.exception.DataAccessException.class, () ->
-            dslContext.insertInto(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME))
-        .columns(
-            field(name("container_id")),
-            field(name("container_state")),
-            field(name("in_state_since")),
-            field(name("expected_replica_count")),
-            field(name("actual_replica_count")),
-            field(name("replica_delta")),
-            field(name("reason"))
-        )
-        .values(999L, "INVALID_STATE", System.currentTimeMillis(), 3, 2, 1,
-            "Invalid state test").execute(),
-        "Inserting an invalid container_state should fail due to the 
constraint");
-  }
-
-  @Test
-  public void testInsertionWithNullContainerState() {
-    assertThrows(org.jooq.exception.DataAccessException.class, () -> {
-      dslContext.insertInto(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME))
-          .columns(
-              field(name("container_id")),
-              field(name("container_state")),
-              field(name("in_state_since")),
-              field(name("expected_replica_count")),
-              field(name("actual_replica_count")),
-              field(name("replica_delta")),
-              field(name("reason"))
-          )
-          .values(
-              100L, // container_id
-              null, // container_state is NULL
-              System.currentTimeMillis(), 3, 2, 1, "Testing NULL state"
-          )
-          .execute();
-    }, "Inserting a NULL container_state should fail due to the NOT NULL 
constraint");
-  }
-
-  @Test
-  public void testDuplicatePrimaryKeyInsertion() throws SQLException {
-    // Insert the first record
-    dslContext.insertInto(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME))
-        .columns(
-            field(name("container_id")),
-            field(name("container_state")),
-            field(name("in_state_since")),
-            field(name("expected_replica_count")),
-            field(name("actual_replica_count")),
-            field(name("replica_delta")),
-            field(name("reason"))
-        )
-        .values(200L, "MISSING", System.currentTimeMillis(), 3, 2, 1, "First 
insertion"
-        )
-        .execute();
-
-    // Try inserting a duplicate record with the same primary key
-    assertThrows(org.jooq.exception.DataAccessException.class, () -> {
-      dslContext.insertInto(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME))
-          .columns(
-              field(name("container_id")),
-              field(name("container_state")),
-              field(name("in_state_since")),
-              field(name("expected_replica_count")),
-              field(name("actual_replica_count")),
-              field(name("replica_delta")),
-              field(name("reason"))
-          )
-          .values(200L, "MISSING", System.currentTimeMillis(), 3, 2, 1, 
"Duplicate insertion"
-          )
-          .execute();
-    }, "Inserting a duplicate primary key should fail due to the primary key 
constraint");
-  }
-
-}
diff --git 
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestReconTaskStatusTableUpgradeAction.java
 
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestReconTaskStatusTableUpgradeAction.java
index 2d98bba6ab1..a7b43a1aeba 100644
--- 
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestReconTaskStatusTableUpgradeAction.java
+++ 
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestReconTaskStatusTableUpgradeAction.java
@@ -17,10 +17,13 @@
 
 package org.apache.hadoop.ozone.recon.upgrade;
 
+import static 
org.apache.ozone.recon.schema.ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME;
 import static 
org.apache.ozone.recon.schema.ReconTaskSchemaDefinition.RECON_TASK_STATUS_TABLE_NAME;
 import static org.apache.ozone.recon.schema.SqlDbUtils.TABLE_EXISTS_CHECK;
 import static org.apache.ozone.recon.schema.SqlDbUtils.columnExists;
+import static org.apache.ozone.recon.schema.SqlDbUtils.constraintExists;
 import static org.apache.ozone.recon.schema.SqlDbUtils.isColumnNullable;
+import static org.jooq.impl.DSL.name;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -42,6 +45,7 @@ public class TestReconTaskStatusTableUpgradeAction extends 
AbstractReconSqlDBTes
 
   private static final String LAST_TASK_RUN_STATUS = "last_task_run_status";
   private static final String IS_CURRENT_TASK_RUNNING = 
"is_current_task_running";
+  private static final String UNHEALTHY_CONTAINERS_CONSTRAINT = 
UNHEALTHY_CONTAINERS_TABLE_NAME + "ck1";
 
   private DSLContext dslContext;
   private DataSource dataSource;
@@ -98,6 +102,17 @@ public void testNoOpWhenTableMissing() throws SQLException {
     assertDoesNotThrow(() -> upgradeAction.execute(dataSource));
   }
 
+  @Test
+  public void testExecuteAppliesUnhealthyContainersConstraint() throws 
Exception {
+    createUnhealthyContainersTableWithoutCheckConstraint();
+
+    upgradeAction.execute(dataSource);
+
+    try (Connection conn = dataSource.getConnection()) {
+      assertTrue(constraintExists(conn, UNHEALTHY_CONTAINERS_TABLE_NAME, 
UNHEALTHY_CONTAINERS_CONSTRAINT));
+    }
+  }
+
   private void createLegacyTaskStatusTable() throws SQLException {
     dropTaskStatusTableIfPresent();
     try (Connection conn = dataSource.getConnection()) {
@@ -124,4 +139,18 @@ private void dropTaskStatusTableIfPresent() throws 
SQLException {
       }
     }
   }
+
+  private void createUnhealthyContainersTableWithoutCheckConstraint() throws 
SQLException {
+    try (Connection conn = dataSource.getConnection()) {
+      if (TABLE_EXISTS_CHECK.test(conn, UNHEALTHY_CONTAINERS_TABLE_NAME)) {
+        dslContext.dropTable(UNHEALTHY_CONTAINERS_TABLE_NAME).execute();
+      }
+    }
+    dslContext.createTable(UNHEALTHY_CONTAINERS_TABLE_NAME)
+        .column("container_id", SQLDataType.BIGINT.nullable(false))
+        .column("container_state", SQLDataType.VARCHAR(16).nullable(false))
+        .constraint(DSL.constraint("pk_container_id")
+            .primaryKey(name("container_id"), name("container_state")))
+        .execute();
+  }
 }
diff --git 
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainerReplicaMismatchAction.java
 
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainerReplicaMismatchAction.java
index 3b58d884609..5f9b1812785 100644
--- 
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainerReplicaMismatchAction.java
+++ 
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestUnhealthyContainerReplicaMismatchAction.java
@@ -20,15 +20,20 @@
 import static 
org.apache.ozone.recon.schema.ContainerSchemaDefinition.UNHEALTHY_CONTAINERS_TABLE_NAME;
 import static org.apache.ozone.recon.schema.SqlDbUtils.TABLE_EXISTS_CHECK;
 import static org.apache.ozone.recon.schema.SqlDbUtils.constraintExists;
+import static org.jooq.impl.DSL.field;
 import static org.jooq.impl.DSL.name;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.sql.Connection;
 import java.sql.SQLException;
 import javax.sql.DataSource;
 import org.apache.hadoop.ozone.recon.persistence.AbstractReconSqlDBTest;
+import 
org.apache.ozone.recon.schema.ContainerSchemaDefinition.UnHealthyContainerStates;
 import org.jooq.DSLContext;
+import org.jooq.exception.DataAccessException;
 import org.jooq.impl.DSL;
 import org.jooq.impl.SQLDataType;
 import org.junit.jupiter.api.BeforeEach;
@@ -68,6 +73,30 @@ public void testNoOpWhenTableMissing() throws SQLException {
     assertDoesNotThrow(() -> upgradeAction.execute(dataSource));
   }
 
+  @Test
+  public void testConstraintAdmitsAllStatesAndRejectsInvalid() throws 
Exception {
+    upgradeAction.execute(dataSource);
+
+    UnHealthyContainerStates[] states = UnHealthyContainerStates.values();
+    for (int i = 0; i < states.length; i++) {
+      insertContainerState(i, states[i].name());
+    }
+    assertEquals(states.length,
+        dslContext.fetchCount(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME)),
+        "Expected one record for each valid state");
+
+    assertThrows(DataAccessException.class,
+        () -> insertContainerState(states.length, "INVALID_STATE"),
+        "Inserting an invalid container_state should fail due to the check 
constraint");
+  }
+
+  private void insertContainerState(long containerId, String containerState) {
+    dslContext.insertInto(DSL.table(UNHEALTHY_CONTAINERS_TABLE_NAME))
+        .columns(field(name("container_id")), field(name("container_state")))
+        .values(containerId, containerState)
+        .execute();
+  }
+
   private void createTableWithoutCheckConstraint() throws SQLException {
     dropTableIfPresent();
     dslContext.createTable(UNHEALTHY_CONTAINERS_TABLE_NAME)


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

Reply via email to